import MailTemp from './MailTemp';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { nowSeconds } from '../pubUtils/timeUtil';
import { MAIL_STATUS } from '../consts/constModules/mailConst';

@index({ roleId: 1 })

export default class Mail extends MailTemp {

    @prop({ required: true })
    roleId: string;

    @prop({ required: true, default: MAIL_STATUS.CREATE })
    status: number;

    /**
     * @description 根据玩家id获得所有有效邮件
     * @param {String} roleId 玩家id
     */
    public static async findByRoleId(roleId: string) {
        const result: MailType[] = await MailModel.find({ 
            roleId, 
            status: { $in: [ MAIL_STATUS.CREATE, MAIL_STATUS.READ, MAIL_STATUS.RECEIVED ] }, 
            sendTime: { $lte: nowSeconds()} ,
            endTime: { $gte: nowSeconds() } 
        }).populate('mail').lean();
        return result;
    }

    /**
     * @description 创建邮件
     * @param {MailTypeParam} params 邮件内容
     */
    public static async addMail(params: MailTypeParam) {
        const doc = new MailModel();
        const mail = Object.assign(doc.toJSON(), params);
        delete mail._id;
        let rec: MailType = await MailModel.findByIdAndUpdate(doc._id, mail, { new: true, upsert: true }).lean();
        return rec;
    }

    /**
     * 根据id更新单个邮件状态
     * @param _id 
     * @param status 邮件状态
     * @param conditions 可更新邮件状态
     */
    public static async updateStatusWithCondition(_id: string, status: MAIL_STATUS) {
        const result: MailType = await MailModel.findOneAndUpdate(
            { _id, sendTime:{$lte: nowSeconds()} }, 
            { $set: { status } }, { new: true }
        ).lean();
        return result;
    }
    
    /**
     * 根据id更新多条邮件状态
     * @param ids 
     * @param status 
     * @param lean 
     */
    public static async updateStatusByIds(ids: string[], status: number, lean = true) {
        let mails = [];
        for(let id of ids) {
            const result: MailType = await MailModel.findOneAndUpdate({_id: id}, { $set:{ 'status': status } }, { new: true }).lean(lean);
            mails.push({id: result._id, status: result.status, /* mailType: MAIL_TYPE.SINGLEMAIL */});
        }
        return mails;
    }

    /**
     * 根据id删除单条邮件
     * @param _id 
     */
    public static async delMailById(_id: string) {
        const result: MailType = await MailModel.findOneAndUpdate(
            { _id, $or: [{ $and: [{ status: MAIL_STATUS.READ, hasGoods: false }] }, { status: MAIL_STATUS.RECEIVED }], sendTime:{$lte: nowSeconds()} }, 
            { $set: { status: MAIL_STATUS.DELETE } }, 
            { new: true }
            ).lean();
        return result;
    }

    /**
     * 根据玩家id批量删除
     * @param _id 
     * @param roleId 
     */
    public static async delMailsByRoleId(roleId: string) {
        const ids: { _id: string }[] = await MailModel.find({ roleId, $or: [{ $and: [{ status: MAIL_STATUS.READ, hasGoods: false }] }, { status: MAIL_STATUS.RECEIVED }], sendTime:{$lte: nowSeconds()} }).select('_id').lean();
        let result: MailType[] = [];
        for(let _id of ids) {
            let rec = await MailModel.findByIdAndUpdate(_id, { $set:{ status: MAIL_STATUS.DELETE }}, { new: true }).lean();
            result.push(rec);
        }
        return result;
    }

    public static async getMail(roleId: string, mailId: string, mailTemType: number, lean = true) {
        const result: MailType = await MailModel.findOne({ roleId, mailId, mailTemType, sendTime:{$lte: nowSeconds()} }).lean(lean);
        return result;
    }

    public static async getMailById(_id: string, lean = true) {
        const result: MailType = await MailModel.findOne({ _id, sendTime:{$lte: nowSeconds()} }).lean(lean);
        return result;
    }


    public static async updateMail(_id: string, update: MailTypeParam, lean = true) {
        const result: MailType = await MailModel.findOneAndUpdate({ _id, sendTime:{$lte: nowSeconds()} }, { $set: update }, { new: true }).lean(lean);
        return result;
    }

    public static async findByTimeGap(beforeTime: number, time: number) {
        const result: MailType[] = await MailModel.find({ sendTime: { $gt: beforeTime, $lte: time } }).lean();
        return result;
    }

    public static async findBySendTime(time: number) {
        const result: MailType[] = await MailModel.find({ sendTime: time }).lean();
        return result;
    }

    /**
     * 查询有奖励的邮件
     * @param roleId 
     * @param lean 
     */
    public static async findRewardsMails(roleId: string, lean = true) {
        const result: MailType[] = await MailModel.find({ roleId, status: {$in: [ MAIL_STATUS.CREATE, MAIL_STATUS.READ ] }, sendTime:{$lte: nowSeconds()} }).lean(lean);
        return result;
    }
}

export const MailModel = getModelForClass(Mail);

export interface MailType extends Pick<DocumentType<Mail>, keyof Mail> { };
export type MailTypeParam = Partial<MailType>; // 将所有字段变成可选项
