const Message = require('./message.js').Message
    ,MeMessage = require('./message.js').MeMessage
    ,NoticeMessage = require('./message.js').NoticeMessage
    ,RoomHistory = require('./message.js').RoomHistory;

/**
 * @constructor
 * @extends {RoomHistory}
 * @param {Slack} ctx
 * @param {string} serviceId
 * @param {Room|string} room or roomId
 * @param {string} idPrefix
 * @param {number} keepMessages number of messages to keep in memory
 * @param {number} maxAge number of messages to keep in memory
 * @param {Array=} evts
 * @param {number=} now
**/
function SlackHistory(ctx, remoteId, room, idPrefix, keepMessages, maxAge, evts, now) {
    RoomHistory.call(this, room, keepMessages, maxAge, evts, now);

    /** @const @type {string} */
    this.remoteId = remoteId;

    /** @const @type {string} */
    this.idPrefix = idPrefix;

    /** @const @type {Slack} */
    this.ctx = ctx;
}
SlackHistory.prototype = Object.create(RoomHistory.prototype);
SlackHistory.prototype.constructor = SlackHistory;

SlackHistory.prototype.prepareMessage = function(ev, targetId) {
    if (ev) {
        if (ev["edited"] && ev["edited"]["ts"])
            ev["edited"] = Math.round(parseFloat(ev["edited"]["ts"]) * 1000);
        if (ev["ts"])
            ev["ts"] = parseFloat(ev["ts"]) * 1000;
        if (!ev["id"])
            ev["id"] = targetId;
        if (ev["attachments"] && ev["attachments"].length)
            ev["attachments"].forEach((a) => {
                a.ts *= 1000;
            });
    }
    return ev;
}

SlackHistory.prototype.messageFactory = function(ev, ts) {
    let img;
    if (ev["file"] && ev["file"]["mimetype"].indexOf("image/") >= 0)
        img = ev["file"]["thumb_360"] || ev["file"]["url_private"] || ev["file"]["permalink"] || undefined;
    if (img) {
        if (!ev["attachments"])
            ev["attachments"] = [];
        ev["attachments"].push({
            "image_url": img
        });
    }
    if (!ev["user"]) {
        if (ev["bot_id"])
            ev["user"] = ev["bot_id"];
        if (ev["comment"] && ev["comment"]["user"])
            ev["user"] = ev["comment"]["user"];
    }
    ev["user"] = this.idPrefix +ev["user"];
    if (ev["reactions"]) {
        ev["reactions"].forEach((r) => {
            for (var i =0, nbUsers =r["users"].length; i < nbUsers; i++)
                r["users"][i] = this.idPrefix +r["users"][i];
        });
    }
    if (ev["is_ephemeral"] === true)
        return new NoticeMessage(ev, ts);
    if (ev["subtype"] === "me_message")
        return new MeMessage(ev, ts);
    return new Message(ev, ts);
};

/**
 * @param {Object} ev
 * @param {number} t
 * @param {resultRef=} m
 * @return {number} ts
**/
SlackHistory.prototype.push = function(ev, t, resultRef) {
    var msg;
    if (!ev["type"] || ev["type"] === "message") {
        var exists = false
            ,targetId = ev["ts"]
            ,modifArg = ev;

        if (ev["subtype"] === "message_changed") {
            if (ev["previous_message"])
                targetId = ev["previous_message"]["ts"];
            else if (ev["message"])
                targetId = ev["message"]["ts"];
            modifArg = ev["message"]
        } else if (ev["subtype"] === "message_deleted" && (ev["previous_message"] || ev["deleted_ts"])) {
            if (ev["previous_message"])
                targetId = ev["previous_message"]["ts"];
            else
                targetId = ev["deleted_ts"];
            modifArg = null;
        } else if (ev["subtype"] === "star_changed") {
            modifArg = ev["message"];
            targetId = ev["message"]["ts"];
        }
        msg = this.getMessageById(targetId);
        if (msg) {
            if (ev["subtype"] === "message_changed" && msg.starred)
                modifArg["is_starred"] = true;
            msg.update(this.prepareMessage(modifArg), t);
            exists = true;
        } else {
            this.prepareMessage(ev["previous_message"], targetId);
            this.prepareMessage(ev["message"], targetId);
            var msgSource = ev["previous_message"] || ev["message"];
            if (msgSource) {
                msg = this.messageFactory(msgSource, t);
                msg.update(modifArg, t);
            } else {
                msg = this.messageFactory(this.prepareMessage(ev, targetId), t);
            }
            this.messages.push(msg);
        }
    } else if (ev["type"] === "reaction_added") {
        msg = this.addReaction(ev["reaction"], this.idPrefix +ev["user"], ev["item"]["ts"], t);
        if (!msg) {
            let self = this;
            this.ctx.fetchHistory(this.ctx.getChatContext().channels[this.id], (msg) => {
                if (msg && msg.length) {
                    msg[0].version = t;
                    self.messages.push(msg[0]);
                    self.resort();
                    self.v = Math.max(self.v, t);
                    self.ctx.getChatContext().liveV = Math.max(self.ctx.getChatContext().liveV, t);
                }
            }, 1, ev["item"]["ts"]);
        }
    } else if (ev["type"] === "reaction_removed") {
        let self = this;
        msg = this.removeReaction(ev["reaction"], this.idPrefix +ev["user"], ev["item"]["ts"], t);
        if (!msg) {
            this.ctx.fetchHistory(this.ctx.getChatContext().channels[this.id], (msg) => {
                if (msg && msg.length) {
                    msg[0].version = t;
                    self.messages.push(msg[0]);
                    self.resort();
                    self.v = Math.max(self.v, t);
                    self.ctx.getChatContext().liveV = Math.max(self.ctx.getChatContext().liveV, t);
                }
            }, 1, ev["item"]["ts"]);
        }
    } else if (ev["type"] === "star_added" || ev["type"] === "star_removed") {
        ev["item"]["subtype"] = "star_changed";
        return this.push(ev["item"], t, resultRef);
    } else {
        return 0;
    }
    this.cleanOld(t);
    if (resultRef)
        resultRef.msg = msg;
    return msg ? msg.ts : 0;
};

SlackHistory.prototype.resort = function() {
    this.messages.sort(function(a, b) {
        return a.ts -b.ts;
    });
};

module.exports.SlackHistory = SlackHistory;

