/**
 * 邮件的模板，在GM后台能看到的邮件列表
 */
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, mongoose, ReturnModelType } from '@typegoose/typegoose';
import { GM_MAIL_STATUS, GM_MAIL_TYPE, MAIL_TIME_TYPE } from '../consts';
import { SearchMailParam } from '../domain/backEndField/search';
import { getCurDay, nowSeconds } from '../pubUtils/timeUtil';
import { GMMail as StategyMail } from './ServerStategy';
import { ServerlistType } from './Serverlist';
import moment = require('moment');

class Reward {
    @prop({ required: true })
    id: number;
    @prop({ required: true })
    count: number;
}

export class Receiver {
    @prop({ required: true })
    env: string;
    @prop({ required: true })
    serverId: number;
    @prop({ required: true })
    roleId?: string;
    @prop({ required: true })
    roleName?: string;
}

export default class GMMail extends BaseModel {

    @prop({ required: false})
    hasGoods: boolean;                 // 有效时间，单位小时

    @prop({ required: true, type: Reward, default: [], _id: false })
    goods: Reward[];

    @prop({ required: true, default: true })
    timeType: MAIL_TIME_TYPE;          // 邮件时间类型

    @prop({ required: false})
    expire: number;                 // 有效时间，单位小时

    @prop({ required: true })
    startTime: number;               // 发送时间，延时邮件使用

    @prop({ required: true })
    circleStart: number;               // 循环邮件开始循环时间

    @prop({ required: true })
    circleEnd: number;               // 循环邮件结束循环时间

    @prop({ required: true })
    circleDay: number;               // 循环时间，每周几，0表示每天

    @prop({ required: true })
    circleHour: string;               // 几点发送

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

    @prop({ required: true })
    content: string;
    
    @prop({ required: true })
    sendName: string;
    
    @prop({ required: true })
    mailType: GM_MAIL_TYPE;         // 收件人类型

    @prop({ required: true, type: Receiver, _id: false })
    receivers: Receiver[];

    @prop({ required: true })
    reason: string;                   // 原因

    @prop({ required: true, default: false })
    isSp: boolean;                   // 特殊邮件

    @prop({ required: true, default: 0 })
    status: GM_MAIL_STATUS;           // 邮件状态

    @prop({ required: true })
    viewBy: number;                   // 审核人

    @prop({ required: true })
    viewAt: Date;                   // 审核时间

    @prop({ required: true, type: Number })
    sendTimes: number[];           // 是否已经发件

    @prop({ required: true })
    sendTime: string;                   // 发送时间

    public setByRegionStategy(type: 'openMail'|'circleMail', gmmail: StategyMail, newServer: ServerlistType, uid) {
        this.hasGoods = !!gmmail.goods?.length;
        this.goods = gmmail.goods;
        this.timeType = type == 'openMail'? MAIL_TIME_TYPE.DELAY: MAIL_TIME_TYPE.CIRCLE;
        this.expire = gmmail.expire;
        if(type == 'openMail') {
            this.startTime = nowSeconds();
        } else {
            this.circleStart = nowSeconds();
            this.circleEnd = nowSeconds() + gmmail.circleContinueDay * 24 * 60 * 60;
            this.circleDay = gmmail.circleDay;
            this.circleHour = gmmail.circleHour;
        }
        this.title = gmmail.title;
        this.content = gmmail.content;
        this.sendName = gmmail.sendName;
        this.mailType = GM_MAIL_TYPE.SERVER;
        this.receivers = [{ 
            env: newServer.env,
            serverId: newServer.id
        }];
        this.reason = gmmail.reason;
        this.isSp = gmmail.isSp;
        this.status = GM_MAIL_STATUS.PASS;
        this.viewBy = uid;
        this.viewAt = new Date();
        if (type == 'openMail') {
            this.sendTime = moment(this.startTime * 1000).format('YYYY-MM-DD HH:mm:ss');
        } else {
            this.sendTime = (this.circleDay == 0?'每天': '每周'+this.circleDay) + ' ' + this.circleHour;
        }
    }

    public static async addMail(params: GMMailTypeParam, uid = 1) {
        const doc = new GMMailModel();
        let mail = Object.assign(doc.toJSON(), params);
        let result: GMMailType = await GMMailModel.findOneAndUpdate({ _id: mail._id }, { $set: {...mail, updatedBy: uid}, $setOnInsert: { createdBy: uid } }, {upsert: true, new: true}).lean();
        return result;
    }

    public static async updateMailById(_id: string, params: GMMailTypeParam, uid: number = 1) {
        let mail: GMMailType = await GMMailModel.findByIdAndUpdate(_id, { $set: {...params, updatedBy: uid}}, {new: true}).lean();
        return mail;
    }

    public static async getGmMailById(_id: string, lean = true) {
        const result: GMMailType = await GMMailModel.findOne({ _id }).lean(lean);
        return result;
    }

    public static async getGmMailByIdAndType(_id: string, mailType: GM_MAIL_TYPE, hasGoods: boolean) {
        const result: GMMailType = await GMMailModel.findOne({ _id, mailType, hasGoods }).lean();
        return result;
    }

    private static getSearchObj(form: SearchMailParam) {
        let searchObj = {};
        if(form.createTimeStart) searchObj['createdAt'] = { $gt: new Date(form.createTimeStart * 1000) };
        if(form.createTimeEnd) searchObj['createdAt'] = { $lt: new Date(form.createTimeEnd * 1000) };
        if(form.serverId) searchObj['receivers.serverId'] = form.serverId;
        if(form.roleId) searchObj['receivers.roleId'] = form.roleId;
        if(form.roleName) searchObj['receivers.roleName'] = { $regex: new RegExp(form.roleName.toString(), 'i') }
        if(form.status) searchObj['status'] = form.status;
        if(form.mailType) searchObj['mailType'] = form.mailType;
        if(form.hasGoods != undefined) searchObj['hasGoods'] = form.hasGoods;
        if(form.title) searchObj['title'] = { $regex: new RegExp(form.title.toString(), 'i') }
        return searchObj
      }

    public static async findByCondition(page: number, pageSize: number, sortField: string, sortOrder: string, form: SearchMailParam = {}) {

        let searchObj = this.getSearchObj(form);
        let sort = {};
        if(sortField && sortOrder) {
            if(sortOrder == 'ascend') {
                sort[sortField] = 1;
            } else if (sortOrder == 'descend') {
                sort[sortField] = -1;
            }
        }
        const result: GMMailType[] = await GMMailModel.find(searchObj).limit(pageSize).skip((page - 1) * pageSize).sort(sort).lean({ getters: true, virtuals: true });
        return result;

    }

    public static async countByCondition(form: SearchMailParam = {}) {

        let searchObj = this.getSearchObj(form);
        const result = await GMMailModel.count(searchObj);
        return result;
    }

    public static async findCircleMails(env: string) {
        const result: GMMailType[] = await GMMailModel.find({ 
            timeType: MAIL_TIME_TYPE.CIRCLE, 
            circleStart: { $lt: nowSeconds() }, circleEnd: { $gte: nowSeconds() },
            circleDay: { $in: [0, getCurDay(true)] }, 'receivers.env': env,
            status: GM_MAIL_STATUS.PASS
        });
        return result;
    }

    public static async sendMail(id: string, time: number) {
        const result: GMMailType = await GMMailModel.findByIdAndUpdate(id, { $push: { sendTimes: time}}, {new: true}).lean();
        return result;
    }

}

export let GMMailModel: ReturnModelType<typeof GMMail, {}>;
export function loadGMMailModel(connect: mongoose.Connection) {
    GMMailModel = getModelForClass(GMMail, {
        existingConnection: connect
    });
}

export interface GMMailType extends Pick<DocumentType<GMMail>, keyof GMMail> { };

export type GMMailTypeParam = Partial<GMMailType>; // 将所有字段变成可选项