import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose';
import Marquee, { MarqueeType } from './Marquee';
import Notice, { NoticeType } from './Notice';
import GMMail from './GMMail';
import { genCode } from '../pubUtils/util';
import { GMMailType } from './GMMail';

/**
  * 开服策略
*/
@index({ id: 1 })

export default class Maintenance extends BaseModel {

    @prop({ required: true })
    code: string;          // 策略唯一标志

    @prop({ required: true, type: Number })
    serverIds: number[];    // 服务器类型

    @prop({ required: true })
    isOpen: boolean;       // 维护是否使用

    @prop({ required: true })
    startTime: Date;       // 维护开始时间

    @prop({ ref: () => Marquee, type: mongoose.Schema.Types.ObjectId })
    marquee: Ref<Marquee>;      // 跑马灯，连接到marquee表

    @prop({ ref: () => Notice, type: mongoose.Schema.Types.ObjectId })
    notice: Ref<Notice>;        // 维护公告

    @prop({ ref: () => GMMail, type: mongoose.Schema.Types.ObjectId })
    mail: Ref<GMMail>;          // 维护结束邮件


    public static async createData(values: MaintenanceTypeParam, marquee: MarqueeType, notice: NoticeType, mail: GMMailType, uid = 1) {
        const code = genCode(8);
        const rec: MaintenanceType = await MaintenanceModel.findOneAndUpdate({ code }, { 
            $setOnInsert: {...values, code, isOpen: false, marquee: marquee._id, notice: notice._id, mail: mail._id, createdBy: uid}, $set: { updatedBy: uid }
         }, { new: true, upsert: true }).lean();
         return rec;
    }

    public static async updateData(code: string, values: MaintenanceTypeParam, uid = 1) {
        const rec: MaintenanceType = await MaintenanceModel.findOneAndUpdate({ code }, { $set: { ...values, updatedBy: uid } }, { new: true, upsert: true })
        .populate('marquee', 'code')
        .populate('notice')
        .populate('mail')
        .lean();
        return rec;
    }

    public static async findOpenMaintenance() {
        const rec: MaintenanceType = await MaintenanceModel.findOne({ isOpen: true }, { _id: 0 }).populate('marquee').populate('notice').populate('mail').lean();
        return rec;
    }

    public static async findByCode(code: string) {
        const rec: MaintenanceType = await MaintenanceModel.findOne({ code }).populate('marquee').populate('notice').populate('mail').lean();
        return rec;
    }

    public static async updateStatusByCode(code: string, isOpen: boolean, uid = 1) {
        const rec: MaintenanceType = await MaintenanceModel.findOneAndUpdate({ code }, { $set: { isOpen, updatedBy: uid } }).populate('marquee').populate('notice').populate('mail').lean();
        return rec;
    }

    private static getSearchObj(form: { isOpen?: boolean }) {
        let searchObj = {};
        if (form.isOpen) searchObj['isOpen'] = form.isOpen;
        return searchObj
    }

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

        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: MaintenanceType[] = await MaintenanceModel.find(searchObj, { _id: 0 })
        .populate('marquee').populate('notice', '+showStartTime +showEndTime').populate('mail')
        .limit(pageSize).skip((page - 1) * pageSize).sort(sort).lean({ getters: true, virtuals: true });
        return result;

    }

    public static async countByCondition(form: { isOpen?: boolean } = {}) {

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


}

export const MaintenanceModel = getModelForClass(Maintenance);

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