import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose';
import { GIFT_GENERATE_TYPE } from '../consts';
import { GiftCodeModel, GiftCodeType } from './GiftCode';
import { nowSeconds } from '../pubUtils/timeUtil';
import { genCode } from '../pubUtils/util';
import { SearchGiftCodeDetailParam } from '../domain/backEndField/search';

class RoleRecord {
    @prop({ required: true, default: '' })
    roleId: string;

    @prop({ required: true, default: '' })
    roleName: string;

    @prop({ required: true, default: 0 })
    serverId: number;

    @prop({ required: true, default: 0 })
    time: number;
}

/**
  * 领取记录
**/
@modelOptions({ schemaOptions: { id: false } })
@index({ code: 1, giftId: 1 })
export default class GiftCodeDetail extends BaseModel {

    @prop({ required: true, default: '' })
    giftId: number;           // giftCode表的id

    @prop({ required: true, default: '' })
    giftName: string;           // giftCode表的name

    @prop({ required: true, default: 0, enum: GIFT_GENERATE_TYPE })
    generateType: GIFT_GENERATE_TYPE;       // 一人一码or通码

    @prop({ required: true, default: '' })
    code: string;           // 兑换码

    @prop({ required: true, default: '' })
    usedNum: number;           // 该码使用次数

    @prop({ required: true, type: String })
    roleIds: string[];

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


    // 根据code
    public static async findByCode(code: string) {
        let result: GiftCodeDetailType = await GiftCodeDetailModel.findOne({ code }).lean(true);
        return result;
    }

    public static async checkHasUsed(roleId: string, id: number) {
        let result = await GiftCodeDetailModel.exists({ giftId: id, 'record.roleId': roleId });
        return result;
    }

    public static async findAllCodeByGiftId(id: number, cnt: number) {
        let n = Math.ceil(cnt/1000);
        let result: GiftCodeDetailType[] = [];
        for(let i = 0; i < n; i++) {
            let codes = await GiftCodeDetailModel.find({ giftId: id }).limit(1000).skip(i * 1000).sort({ _id: 1 }).lean();
            result.push(...codes);
        }
        return result;
    }

    public static async increaseUsedNum(code: string, roleId: string, roleName: string, serverId: number) {
        let result: GiftCodeDetailType = await GiftCodeDetailModel.findOneAndUpdate({ code }, { 
            $inc: { usedNum: 1 }, $push: { roleIds: roleId, record: { roleId, roleName, serverId, time: nowSeconds() } }
        }, { new: true }).lean();
        return result;
    }

    public static async generateMany(giftCode: GiftCodeType, count = 1, uid = 1) {
        let insertArr: GiftCodeDetailParam[] = [];
        for(let i = 0; i < count; i++) {
            insertArr.push({ 
                giftId: giftCode.id, giftName: giftCode.name, generateType: giftCode.generateType, 
                code: giftCode.code||genCode(giftCode.codeLen), usedNum: 0, createdBy: uid, updatedBy: uid 
            });
        }
        let result = await GiftCodeDetailModel.insertMany(insertArr);
        await GiftCodeModel.increateGenerateNum(giftCode.id, count);
        return result;
    }

    private static getSearchObj(form: SearchGiftCodeDetailParam) {
        let searchObj = {};
        if(form.giftId) searchObj['giftId'] = form.giftId;
        if (form.giftName != undefined) searchObj['giftName'] = { $regex: new RegExp(form.giftName.toString(), 'i') };
        if(form.generateType) searchObj['generateType'] = form.generateType;
        if(form.code) searchObj['code'] = form.code;
        if(form.roleId) searchObj['record.roleId'] = form.roleId;
        if (form.roleName != undefined) searchObj['record.roleName'] = { $regex: new RegExp(form.roleName.toString(), 'i') };
        return searchObj
    }

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

        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: GiftCodeDetailType[] = await GiftCodeDetailModel.find(searchObj, { _id: 0 }).limit(pageSize).skip((page - 1) * pageSize).sort(sort).lean({ getters: true, virtuals: true });
        return result;

    }

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

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

}

export const GiftCodeDetailModel = getModelForClass(GiftCodeDetail);

export interface GiftCodeDetailType extends Pick<DocumentType<GiftCodeDetail>, keyof GiftCodeDetail> { }
export type GiftCodeDetailParam = Partial<GiftCodeDetailType>;
