import { RewardInter, pushMail, mailData } from "../pubUtils/interface";
import { MailModel, MailType } from "../db/Mail";
import { GroupMailModel, GroupMailType } from "../db/GroupMail";
import { ServerMailModel, ServerMailType } from '../db/ServerMail';
import { getRoleOnlineInfo } from "./redisService";
import { pinus } from "pinus";
import { gameData } from "../pubUtils/data";
import { nowSeconds } from '../pubUtils/timeUtil';
import { STATUS } from '../consts/statusCode';
import { resResult } from '../pubUtils/util';
import { GM_MAIL_TYPE, ITID, MAIL_STATUS, MAIL_TYPE, SEND_NAME } from "../consts";
import { MailParam } from '../domain/roleField/mail';
import { GMMailType, GMMailModel } from "../db/GMMail";
import { getGuildChannelSid, getWorldChannelSid } from "./chatChannelService";
import { GMMailRecordModel } from "../db/GMMailRecord";
import { BAG } from "../pubUtils/dicParam";
import { GuildModel, GuildType } from "../db/Guild";

/**
 * 获取邮件信息
 * @param {String} roleId 玩家id 
 * @param {Number} serverId 服务器id
 */
export async function getMails(roleId: string, serverId: number) {
    let mails = await MailModel.findByRoleId(roleId)||[];
    let groupMails = await GroupMailModel.findByRoleId(roleId)||[];
    let serverMails = await ServerMailModel.findByRoleId(roleId, serverId)||[];

    let list = getMailInfos(roleId, mails, groupMails, serverMails);
    list.sort((a, b) => a.sendTime - b.sendTime);
    return list;
}

/**
 * 根据数据库数据，生成返回数据
 * @param {String} roleId 玩家id
 * @param {MailType[]} mails 单人邮件 
 * @param {GroupMailType[]} groupMails 多人邮件 
 * @param {ServerMailType[]} serverMails 全服邮件
 */
function getMailInfos(roleId: string, mails: MailType[], groupMails: GroupMailType[], serverMails: ServerMailType[]) {
    let list: MailParam[] = []; // 结果
    for(let mail of mails) {
        list.push(new MailParam( GM_MAIL_TYPE.SINGLE, mail, roleId));
    }
    for(let mail of groupMails) {
        list.push(new MailParam(GM_MAIL_TYPE.GROUP, mail, roleId));
    }
    for(let mail of serverMails) {
        list.push(new MailParam(GM_MAIL_TYPE.SERVER, mail, roleId));
    }
    return list;
}

export async function sendMailByContent(contentId: MAIL_TYPE, hisRoleId: string, params: { sendName?: string, endTime?: number, params?: string[], goods?: RewardInter[], notPush?: boolean }) {
    let f = new SendMailFun();
    f.setWithContentId(contentId, params);
    await f.sendToUsers(GM_MAIL_TYPE.SINGLE, [hisRoleId]);
}

export async function sendMailToGuildByContent(contentId: MAIL_TYPE, guildCode: string, params: { sendName?: string, endTime?: number, params?: string[], goods?: RewardInter[], notPush?: boolean }, guild?: GuildType) {
    if(!guild) guild = await GuildModel.findByCode(guildCode, null, '+members');
    if(!guild) return false;
    let f = new SendMailFun();
    f.setWithContentId(contentId, params);
    await f.sendToGuild(guildCode, guild.members);
    return true;
}

/**
 * 发送邮件方法类
 */
export class SendMailFun {
    private mailType: GM_MAIL_TYPE = GM_MAIL_TYPE.SINGLE;   // 邮件类型 1-单人 2-多人 3-全服
    private contentId: MAIL_TYPE = MAIL_TYPE.SEND_MAIL;     // 0-读GmMail，1以上读dicMail
    private params: string[] = [];
    private sendName: string = SEND_NAME;
    private gmmail: GMMailType;
    private hasGoods: boolean = false;                      // 是否内含奖励
    private goods: RewardInter[] = [];                      // 发送的奖励
    private sendTime: number;
    private endTime: number;
    private notPush: boolean = false;
    private mails: MailType[] = [];
    private groupMails: GroupMailType[] = [];
    private serverMails: ServerMailType[] = [];

    // 从dicMail读取数据
    public setWithContentId(contentId: MAIL_TYPE, params: { sendName?: string, endTime?: number, params?: string[], goods?: RewardInter[] }) {
        let dicMail = gameData.mail.get(contentId);
        this.contentId = contentId;
        this.sendTime = nowSeconds();
        this.endTime = this.sendTime + dicMail?.time||0;
        this.setParam({ ...params });
    }

    // 从GMMail表读取数据
    public async setWithGmMail(gmmailId: string) {
        let gmmail = await GMMailModel.getGmMailById(gmmailId);
        if(gmmail) {
            this.gmmail = gmmail;
            if(gmmail.useTempTime) {
                this.sendTime = gmmail.sendTime;
                this.endTime = gmmail.endTime;
            } else {
                this.sendTime = nowSeconds();
                this.endTime = this.sendTime + (gmmail.continueHour||0) * 60 * 60;
            }
            this.setParam({ ...gmmail });
        }
    }

    private setParam(params: { sendName?: string, endTime?: number, params?: string[], goods?: RewardInter[], content?: string }) {
        if(params.sendName) this.sendName = params.sendName;
        if(params.endTime) this.endTime = params.endTime;
        if(params.content) {
            this.params.push(params.content);
        }
        if(params.params) this.params = params.params;
        if(params.goods) {
            this.hasGoods = params.goods.length > 0;
            this.goods = params.goods;
        }
    }

    private getCreateMailParams() {
        return {
            contentId: this.contentId, 
            mail: this.gmmail?._id, 
            sendTime: this.sendTime, 
            endTime: this.endTime, 
            params: this.params, 
            goods: this.goods, 
            sendName: this.sendName,
            hasGoods: this.hasGoods
        }
    }

    // 生成单人邮件
    private async createSingleMails(roleIds: string[]) {
        let mails = new Map<string, MailParam>();
        for(let roleId of roleIds) {
            let originMail = await MailModel.addMail({ roleId, ...this.getCreateMailParams() });
            this.mails.push(originMail);
            let mail = new MailParam(this.mailType, originMail);
            mails.set(roleId, mail);
        }

        return mails;
    }

    // 生成多人邮件
    private async createGroupMails(roleIds: string[]) {
        let roleStatus = roleIds.map(roleId => {
            return { roleId, status: MAIL_STATUS.CREATE }
        })
        let originMail = await GroupMailModel.addMail({ roleStatus, ...this.getCreateMailParams() });
        this.groupMails.push(originMail);
        return new MailParam(this.mailType, originMail);
    }

    // 生成全服邮件
    private async createServerMails(serverIds: number[]) {
        let mails = new Map<number, MailParam>();
        for(let serverId of serverIds) {
            let originMail = await ServerMailModel.addMail({ serverId, ...this.getCreateMailParams() });
            mails.set(serverId, new MailParam(this.mailType, originMail));
            this.serverMails.push(originMail);
        }
        return mails
    }

    // 向某几个玩家推送
    public async sendToUsers(mailType: GM_MAIL_TYPE.SINGLE|GM_MAIL_TYPE.GROUP,roleIds: string[], myRoleId?: string, mySid?: string) {
        this.mailType = mailType;
        let uids: { uid: string, sid: string }[] = []
        for(let roleId of roleIds) {
            let sid = '';
            if(roleId == myRoleId) {
                sid = mySid;
            } else {
                let hisOnlineInfo = await getRoleOnlineInfo(roleId);
                if(hisOnlineInfo.isOnline) {
                    sid = hisOnlineInfo.sid;
                }
            }
            if(sid) {
                uids.push({ uid: roleId, sid });
            }
        }

        if(mailType == GM_MAIL_TYPE.SINGLE) {
            let mails = await this.createSingleMails(roleIds);
            for(let { uid, sid } of uids) {
                let mail = mails.get(uid);
                if(uids.length > 0 && mail && !this.notPush) pinus.app.channelService.pushMessageByUids('onMailsAdd', resResult(STATUS.SUCCESS, { mails: [mail] }), [{ uid, sid }]);
            }
        } else if (mailType == GM_MAIL_TYPE.GROUP) {
            let mail = await this.createGroupMails(roleIds);
            if(uids.length > 0 && !this.notPush) pinus.app.channelService.pushMessageByUids('onMailsAdd', resResult(STATUS.SUCCESS, { mails: [mail] }), uids);
        } else { // mailType错误
            return false;
        }
        return true;
    }

    // 向军团推送
    public async sendToGuild(guildCode: string, members: string[]) {
        this.mailType = GM_MAIL_TYPE.GROUP;
        let mails = await this.createGroupMails(members);
        let chatSid = await getGuildChannelSid(guildCode);
        if(!this.notPush) pinus.app.rpc.chat.guildRemote.sendMailToGuild.toServer(chatSid, guildCode, 'onMailsAdd', { mails });
    }

    // 向全服推送
    public async sendToServer(serverIds: number[]) {
        this.mailType = GM_MAIL_TYPE.SERVER;
        let mails = await this.createServerMails(serverIds);
        for(let serverId of serverIds) {
            let mail = mails.get(serverId);
            if(mail && !this.notPush) {
                let chatSid = await getWorldChannelSid(serverId);
                pinus.app.rpc.chat.chatRemote.sendMail.toServer(chatSid, serverId, 'onMailsAdd', { mails: [mail] });
            }
        }
    }

    public async saveRecord(createUid: number) {
        for(let mail of this.mails) {
            await GMMailRecordModel.createRecord(GM_MAIL_TYPE.SINGLE, mail, createUid);
        }
        for(let mail of this.groupMails) {
            await GMMailRecordModel.createRecord(GM_MAIL_TYPE.GROUP, mail, createUid);
        }
        for(let mail of this.serverMails) {
            await GMMailRecordModel.createRecord(GM_MAIL_TYPE.SERVER, mail, createUid);
        }
    }
}

export function checkMailGoods(mail: MailType | GroupMailType | ServerMailType, equipCount: number) {
    let isEquipOver = false;
    for (let good of mail.goods) {
        let dicGoods = gameData.goods.get(good.id);
        let dicItid = ITID.get(dicGoods.itid);
        if (dicItid.table == 'equip') { // 装备
            if (++equipCount > BAG.BAG_EQUIP_UPLIMITED) {
                isEquipOver = true;
                break;
            }
        }
    }

    return {
        isEquipOver, equipCount
    }
}