"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.emitGroupNoticeEvent = emitGroupNoticeEvent;
exports.onlinePushListener = onlinePushListener;
exports.onlinePushTransListener = onlinePushTransListener;
exports.dmMsgSyncListener = dmMsgSyncListener;
exports.groupMsgListener = groupMsgListener;
exports.discussMsgListener = discussMsgListener;
const core_1 = require("../core");
const common_1 = require("../common");
const message_1 = require("../message");
/** OnlinePush回执 */
function handleOnlinePush(svrip, seq, items = []) {
    const resp = core_1.jce.encodeStruct([
        this.uin, items, svrip & 0xffffffff, null, 0
    ]);
    const body = core_1.jce.encodeWrapper({ resp }, "OnlinePush", "SvcRespPushMsg", seq);
    this.writeUni("OnlinePush.RespPush", body);
}
const statuslist = [
    null,
    common_1.OnlineStatus.Online,
    null,
    common_1.OnlineStatus.Absent,
    common_1.OnlineStatus.Invisible,
    common_1.OnlineStatus.Busy,
    common_1.OnlineStatus.Qme,
    common_1.OnlineStatus.DontDisturb,
];
const sub0x27 = {
    0: function (data) {
        this.classes.set(data[3][1], String(data[3][3]));
    },
    1: function (data) {
        this.classes.delete(data[4][1]);
    },
    2: function (data) {
        this.classes.set(data[5][1], String(data[5][2]));
    },
    4: function (data) {
        const arr = Array.isArray(data[7][1]) ? data[7][1] : [data[7][1]];
        for (let v of arr)
            this.fl.get(v[1]).class_id = v[3];
    },
    80: function (data) {
        const o = data[12];
        const gid = o[3];
        if (!o[4])
            return;
        this.gl.get(gid).group_name = String(o[2][2]);
    },
    5: function (data) {
        const user_id = data[14][1];
        const nickname = this.fl.get(user_id)?.nickname || "";
        this.fl.delete(user_id);
        this.logger.info(`更新了好友列表，删除了好友 ${user_id}(${nickname})`);
        return {
            sub_type: "decrease",
            user_id, nickname
        };
    },
    20: function (data) {
        // 20002昵称 20009性别 20031生日 23109农历生日 20019说明 20032地区 24002故乡 27372在线状态
        const uid = data[8][1];
        let o = data[8][2];
        if (Array.isArray(o))
            o = o[0];
        let key, value;
        if (o[1] === 20002) {
            key = "nickname";
            value = String(o[2]);
            this.fl.get(uid).nickname = value;
        }
        else if (o[1] === 20009) {
            key = "sex";
            value = ["unknown", "male", "female"][o[2].toBuffer()[0]];
        }
        else if (o[1] === 20031) {
            key = "age";
            value = new Date().getFullYear() - o[2].toBuffer().readUInt16BE();
        }
        else if (o[1] === 27372 && uid === this.uin) {
            const status = o[2].toBuffer()[o[2].toBuffer().length - 1];
            this.status = statuslist[status] || 11;
            return;
        }
        else {
            return;
        }
        if (uid === this.uin)
            this[key] = value;
    },
    40: function (data) {
        const o = data[9][1], uid = o[2];
        if (o[1] > 0)
            return; //0好友备注 1群备注
        this.fl.get(uid).remark = String(o[3]);
    },
};
// 好友事件解析
const push528 = {
    0x8A: function (buf) {
        let data = core_1.pb.decode(buf)[1];
        if (Array.isArray(data))
            data = data[0];
        let user_id = data[1], operator_id = data[1], flag = 0;
        if (user_id === this.uin) {
            user_id = data[2];
            flag = 1;
        }
        return {
            sub_type: "recall",
            message_id: (0, message_1.genDmMessageId)(user_id, data[3], data[6], data[5], flag),
            operator_id,
            user_id, //永远指向对方
            seq: data[3],
            rand: data[6],
            time: data[5],
        };
    },
    0x8B: function (buf) {
        return push528[0x8A].call(this, buf);
    },
    0xB3: function (buf) {
        const data = core_1.pb.decode(buf)[2];
        const user_id = data[1], nickname = String(data[5]);
        this.fl.set(user_id, {
            user_id: user_id,
            nickname,
            sex: "unknown",
            remark: nickname,
            class_id: data[7]
        });
        this.sl.delete(user_id);
        this.logger.info(`更新了好友列表，新增了好友 ${user_id}(${nickname})`);
        return {
            sub_type: "increase",
            user_id, nickname
        };
    },
    0xD4: function (buf) {
        const gid = core_1.pb.decode(buf)[1];
        this.pickGroup(gid).renew().catch(common_1.NOOP);
    },
    0x27: function (buf) {
        let data = core_1.pb.decode(buf)[1];
        if (Array.isArray(data))
            data = data[0];
        return sub0x27[data[2]]?.call(this, data);
    },
    0x122: function (buf) {
        const data = core_1.pb.decode(buf);
        const e = parsePoke(data);
        if (e.action) {
            e.operator_id = e.operator_id || this.uin;
            e.target_id = e.target_id || this.uin;
            return Object.assign(e, { sub_type: "poke" });
        }
    },
    0x115: function (buf) {
        const data = core_1.pb.decode(buf);
        const user_id = data[1];
        const end = data[3][4] === 2;
        this.emit("internal.input", { user_id, end });
    },
};
function parsePoke(data) {
    let target_id = 0, operator_id = 0, action = "", suffix = "";
    for (let o of data[7]) {
        const name = String(o[1]), val = String(o[2]);
        switch (name) {
            case "action_str":
            case "alt_str1":
                action = action || val;
                break;
            case "uin_str1":
                operator_id = parseInt(val);
                break;
            case "uin_str2":
                target_id = parseInt(val);
                break;
            case "suffix_str":
                suffix = val;
                break;
        }
    }
    return { target_id, operator_id, action, suffix };
}
function parseSign(data) {
    let user_id = this.uin, nickname = "", sign_text = "";
    for (let o of data[7]) {
        const name = String(o[1]), val = String(o[2]);
        switch (name) {
            case "user_sign":
                sign_text = sign_text || val;
                break;
            case "mqq_uin":
                user_id = parseInt(val);
                break;
            case "mqq_nick":
                nickname = val;
                break;
        }
    }
    return { user_id, nickname, sign_text };
}
// 群事件解析
const push732 = {
    0x0C: function (gid, buf) {
        const operator_id = buf.readUInt32BE(6);
        const user_id = buf.readUInt32BE(16);
        let duration = buf.readUInt32BE(20);
        try {
            if (user_id === 0) {
                duration = duration ? 0xffffffff : 0;
                this.gl.get(gid).shutup_time_whole = duration;
            }
            else if (user_id === this.uin)
                this.gl.get(gid).shutup_time_me = duration ? ((0, common_1.timestamp)() + duration) : 0;
            this.gml.get(gid).get(user_id).shutup_time = duration ? ((0, common_1.timestamp)() + duration) : 0;
        }
        catch { }
        this.logger.info(`用户${user_id}在群${gid}被禁言${duration}秒`);
        return {
            sub_type: "ban",
            operator_id, user_id, duration
        };
    },
    0x11: function (gid, buf) {
        const data = core_1.pb.decode(buf.slice(7))[11];
        const operator_id = data[1];
        const msg = Array.isArray(data[3]) ? data[3][0] : data[3];
        const user_id = msg[6];
        const message_id = (0, message_1.genGroupMessageId)(gid, user_id, msg[1], msg[3], msg[2], Array.isArray(data[3]) ? data[3].length : 1);
        return {
            sub_type: "recall",
            user_id, operator_id, message_id,
            seq: msg[1],
            rand: msg[3],
            time: msg[2]
        };
    },
    0x14: function (gid, buf) {
        const data = core_1.pb.decode(buf.slice(7))[26];
        let e = parsePoke(data);
        if (e.action) {
            e.operator_id = e.operator_id || this.uin;
            e.target_id = e.target_id || this.uin;
            return Object.assign(e, {
                sub_type: "poke",
                /** @deprecated */
                user_id: e.target_id
            });
        }
        const sign = { gid };
        Object.assign(sign, parseSign.call(this, data));
        if (sign.sign_text)
            return {
                sub_type: 'sign',
                ...sign
            };
    },
    0x0E: function (gid, buf) {
        if (buf[5] !== 1)
            return;
        const duration = buf.readInt32BE(10);
        if (buf[14] !== 0) {
            const nickname = String(buf.slice(15, 15 + buf[14]));
            const operator_id = buf.readUInt32BE(6);
            this.logger.info(`匿名用户${nickname}在群${gid}被禁言${duration}秒`);
            return {
                sub_type: "ban",
                operator_id,
                user_id: 80000000, nickname,
                duration
            };
        }
    },
};
function emitFriendNoticeEvent(c, uid, e) {
    if (!e)
        return;
    const name = "notice.friend." + e.sub_type;
    const f = c.pickFriend(uid);
    const event = Object.assign({
        post_type: "notice",
        notice_type: "friend",
        user_id: uid,
        friend: f
    }, e);
    c.em(name, event);
}
function emitGroupNoticeEvent(c, gid, e) {
    if (!e)
        return;
    const name = "notice.group." + e.sub_type;
    const group = c.pickGroup(gid);
    const event = Object.assign({
        post_type: "notice",
        notice_type: "group",
        group_id: gid,
        group: group
    }, e);
    c.em(name, event);
}
function onlinePushListener(payload, seq) {
    const nested = core_1.jce.decodeWrapper(payload);
    const list = nested[2], v = list[0];
    const rubbish = core_1.jce.encodeNested([
        this.uin, v[1], v[3], v[8], 0, 0, 0, 0, 0, 0, 0
    ]);
    handleOnlinePush.call(this, nested[3], seq, [rubbish]);
    if (!this._sync_cookie)
        return;
    if (v[2] === 528) {
        const uid = v[0];
        const nested = core_1.jce.decode(v[6]);
        const type = nested[0], buf = nested[10];
        emitFriendNoticeEvent(this, uid, push528[type]?.call(this, buf));
        if (core_1.pb.decode(buf)[1][2] == 214) {
            /** 214上报 */
            const req = core_1.jce.encodeStruct([this.uin, this.device.android_id, 0]);
            const servant = 'VIP.CustomOnlineStatusServer.CustomOnlineStatusObj';
            const func = 'GetCustomOnlineStatus';
            const body = core_1.jce.encodeWrapper({ req }, servant, func);
            this.writeUni(`VipCustom.${func}`, body);
        }
    }
    else if (v[2] === 732) {
        const gid = v[6].readUInt32BE();
        const type = v[6][4];
        emitGroupNoticeEvent(this, gid, push732[type]?.call(this, gid, v[6]));
    }
}
function onlinePushTransListener(payload, seq) {
    const proto = core_1.pb.decode(payload);
    handleOnlinePush.call(this, proto[11], seq);
    if (!this._sync_cookie)
        return;
    const buf = proto[10].toBuffer();
    const gid = buf.readUInt32BE();
    if (proto[3] === 44) {
        if (buf[5] === 0 || buf[5] === 1) {
            const user_id = buf.readUInt32BE(6);
            const set = buf[10] > 0;
            this.logger.info(`群${gid}设置管理员${user_id}: ` + set);
            emitGroupNoticeEvent(this, gid, {
                sub_type: "admin",
                user_id, set
            });
            if (user_id === this.uin)
                this.gl.get(gid).admin_flag = set;
            this.gml.get(gid).get(user_id).role = set ? "admin" : "member";
        }
        else if (buf[5] === 0xFF) {
            const operator_id = buf.readUInt32BE(6);
            const user_id = buf.readUInt32BE(10);
            this.logger.info(`群${gid}被转让给` + user_id);
            emitGroupNoticeEvent(this, gid, {
                sub_type: "transfer",
                operator_id, user_id
            });
            this.gl.get(gid).owner_id = user_id;
            this.gml.get(gid).get(user_id).role = "owner";
            this.gml.get(gid).get(operator_id).role = "member";
        }
    }
    else if (proto[3] === 34) {
        const user_id = buf.readUInt32BE(5);
        let operator_id, dismiss = false;
        let member = this.gml.get(gid)?.get(user_id);
        if (buf[9] === 0x82 || buf[9] === 0x2) {
            operator_id = user_id;
            this.gml.get(gid)?.delete(user_id);
            this.logger.info(`${user_id}离开了群${gid}`);
        }
        else {
            operator_id = buf.readUInt32BE(10);
            if (buf[9] === 0x01 || buf[9] === 0x81)
                dismiss = true;
            if (user_id === this.uin) {
                this.gl.delete(gid);
                this.gml.delete(gid);
                this.logger.info(`更新了群列表，删除了群：${gid}`);
            }
            else {
                this.gml.get(gid)?.delete(user_id);
                this.logger.info(`${user_id}离开了群${gid}`);
            }
        }
        emitGroupNoticeEvent(this, gid, {
            sub_type: "decrease",
            user_id, operator_id, dismiss, member
        });
        this.gl.get(gid).member_count--;
    }
}
function dmMsgSyncListener(payload, seq) {
    const proto = core_1.pb.decode(payload);
    handleOnlinePush.call(this, proto[2], seq);
    const msg = new message_1.PrivateMessage(proto[1], this.uin);
    msg.sender.nickname = this.nickname;
    this.em("sync.message", msg);
}
const fragmap = new Map();
function groupMsgListener(payload) {
    this.stat.recv_msg_cnt++;
    if (!this._sync_cookie)
        return;
    let msg = new message_1.GroupMessage(core_1.pb.decode(payload)[1]);
    this.emit(`internal.${msg.group_id}.${msg.rand}`, msg.message_id);
    if (msg.user_id === this.uin && this.config.ignore_self)
        return;
    //分片专属屎山
    if (msg.pktnum > 1) {
        const k = [this.uin, msg.group_id, msg.user_id, msg.div].join();
        if (!fragmap.has(k))
            fragmap.set(k, []);
        const arr = fragmap.get(k);
        arr.push(msg);
        setTimeout(() => fragmap.delete(k), 5000);
        if (arr.length !== msg.pktnum)
            return;
        msg = message_1.GroupMessage.combine(arr);
    }
    if (msg.raw_message) {
        const group = this.pickGroup(msg.group_id);
        const member = group.pickMember(msg.sender.user_id);
        msg.group = group;
        msg.member = member;
        msg.reply = function (content, quote = false) {
            return this.group.sendMsg(content, quote ? this : undefined);
        };
        msg.recall = function () {
            return this.group.recallMsg(this);
        };
        const sender = msg.sender;
        if (msg.member.info) {
            const info = msg.member.info;
            sender.nickname = info.nickname;
            sender.sex = info.sex;
            sender.age = info.age;
            sender.area = info.area || "";
            info.card = sender.card;
            info.title = sender.title;
            info.level = sender.level;
            info.last_sent_time = (0, common_1.timestamp)();
        }
        this.logger.info(`recv from: [Group: ${msg.group_name}(${msg.group_id}), Member: ${sender.card || sender.nickname}(${sender.user_id})] ` + msg);
        this.em("message.group." + msg.sub_type, msg);
        msg.group.info.last_sent_time = (0, common_1.timestamp)();
    }
}
function discussMsgListener(payload, seq) {
    this.statistics.recv_msg_cnt++;
    const proto = core_1.pb.decode(payload);
    handleOnlinePush.call(this, proto[2], seq);
    if (!this._sync_cookie)
        return;
    const msg = new message_1.DiscussMessage(proto[1]);
    if (msg.user_id === this.uin && this.config.ignore_self)
        return;
    if (msg.raw_message) {
        msg.discuss = this.pickDiscuss(msg.discuss_id);
        msg.reply = msg.discuss.sendMsg.bind(msg.discuss);
        this.logger.info(`recv from: [Discuss: ${msg.discuss_name}(${msg.discuss_id}), Member: ${msg.sender.card}(${msg.sender.user_id})] ` + msg);
        this.em("message.discuss", msg);
    }
}
