import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose';
// import { COUNTER } from '../consts';
// import { CounterModel } from './Counter';
import { SearchJewelParam } from '../domain/backEndField/search';
import { RoleModel } from './Role';
import { CounterModel } from './Counter';
import { COUNTER } from '../consts';
import { HeroModel } from './Hero';

export class JewelSe {
    @prop({ required: true })
    id: number;					// 随机属性位置id
    @prop({ required: true })
    seid: number;					// 随机属性池id
    @prop({ required: true })
    rand: number;					// 随机属性内需要随机的值

    constructor(id: number, seid: number, rand: number) {
        this.id = id;
        this.seid = seid;
        this.rand = rand;
    }
}

export class RandSe extends JewelSe {
    @prop({ required: true })
    preRand?: number;					// 淬炼失败的是随机出的值
    @prop({ required: true })
    locked: boolean = false;				// 洗炼是否锁定

    @prop({ required: false, default: false })
    quenched: boolean = false;				// 是否淬炼了
    @prop({ required: false, default: 0 })
    quenchCnt: number = 0;				// 淬炼次数
}

@index({ roleId: 1, id: 1 })
@index({ seqId: 1 })
@modelOptions({ schemaOptions: { id: false } })
export default class Jewel extends BaseModel {

    @prop({ required: true })
    roleId: string;					// 角色 id
    @prop({ required: true })
    roleName: string;				// 角色名称

    @prop({ required: true })
    seqId: number;					// 装备表自增 id
    @prop({ required: true })
    id: number;						// 装备 id
    @prop({ required: true })
    name: string;					// 装备名称
    @prop({ required: false, default: 0 })
    hid: number;					// 装备此装备的武将 id
    @prop({ required: false, default: 0 })
    ePlaceId: number;				// 武将装备的部位

    @prop({ required: false, type: JewelSe, default: [], _id: false })
    rareSe: JewelSe[];				// 强化随机属性
    @prop({ required: false, type: RandSe, default: [], _id: false })
    randSe: RandSe[];				// 强化随机属性
    @prop({ required: false, type: RandSe, default: [], _id: false })
    previewRandSe: RandSe[];		// 强化随机属性预览

    public static async findbyRole(roleId: string, select = '') {
        const jewels: JewelType[] = await JewelModel.find({ roleId }).select(select).lean();
        return jewels;
    }

    public static async findbyRoleAndHids(roleId: string, hids: number[]) {
        const jewels: JewelType[] = await JewelModel.find({ roleId, hid: { $in: hids } }).lean();
        return jewels;
    }

    public static async findMapbyRoleAndHids(roleId: string, hids: number[]) {
        const jewels = await JewelModel.findbyRoleAndHids(roleId, hids);
        let map = new Map<number, JewelType>();
        for(let jewel of jewels) {
            map.set(jewel.seqId, jewel);
        }
        return map;
    }

    public static async findbySeqId(seqId: number, select?: string ) {
        const jewel: JewelType = await JewelModel.findOne({ seqId }).select(select).lean();
        return jewel;
    }

    public static async findbySeqIds(seqIds: number[], select?: string ) {
        const jewel: JewelType[] = await JewelModel.find({ seqId: { $in: seqIds } }).select(select).lean();
        return jewel;
    }

    public static async createJewel(jewelInfo: jewelUpdate) {
        const seqId = await CounterModel.getNewCounter(COUNTER.JEWEL_ID);

        const doc = new JewelModel();
        const update = Object.assign(doc.toJSON(), seqId, jewelInfo);
        delete update._id;
        const jewel: JewelType = await JewelModel.findOneAndUpdate({ seqId }, update, { upsert: true, new: true }).lean();
        if (jewelInfo.hid > 0) {
            await HeroModel.findOneAndUpdate(
                { roleId: jewelInfo.roleId, hid: jewelInfo.hid, 'ePlace.id': jewelInfo.ePlaceId },
                { $set: { 'ePlace.$.jewel': seqId } },
                { new: true }).lean();
        }
        return jewel;
    }

    public static async createJewels(roleId: string, jewelInfos: jewelUpdate[]) {
        let result: JewelType[] = [];
        for(let jewelInfo of jewelInfos) {
            let jewel = await this.createJewel(jewelInfo);
            result.push(jewel);
        }
        await RoleModel.increaseJewel(roleId, result.length);
        return result;
    }

    public static async putOnOrOff(seqId: number, hid: number, ePlaceId: number) {
        let rec: JewelType = await JewelModel.findOneAndUpdate({ seqId }, { $set: { hid, ePlaceId } }, { new: true }).lean();
        return rec;
    }

    public static async lock(seqId: number, id: number, lock: boolean) {
        let result: JewelType = await JewelModel.findOneAndUpdate({ seqId, 'randSe.id': id }, { $set: { 'randSe.$.locked': lock } }, { new: true }).select('seqId id randSe').lean();
        return result;
    }

    public static async chooseQuench(seqId: number, id: number) {
        let result: JewelType = await JewelModel.findOneAndUpdate({ seqId, 'randSe.id': id }, { $set: { 'randSe.$.quenched': true } }, { new: true }).lean();
        return result;
    }

    public static async quench(seqId: number, isSuccess: boolean, rand: number) {
        if(isSuccess) {
            let result: JewelType = await JewelModel.findOneAndUpdate({ seqId, 'randSe.quenched': true }, { $set: { 'randSe.$.rand': rand } }, { new: true }).lean();
            return result;
        } else {
            let result: JewelType = await JewelModel.findOneAndUpdate({ seqId, 'randSe.quenched': true }, { $inc: { 'randSe.$.quenchCnt': 1 }, $set: { 'randSe.$.preRand': rand } }, { new: true }).lean();
            return result;
        }
    }

    public static async updateInfo(seqId: number, update: jewelUpdate) {
        let result: JewelType = await JewelModel.findOneAndUpdate({ seqId }, { $set: update }, {new: true}).lean();
        return result;
    }

    public static async deleteBySeqIds(roleId: string, seqIds: number[]) {
        let jewels = await JewelModel.findbySeqIds(seqIds);
        await JewelModel.deleteMany({ roleId, seqId: { $in: seqIds } });
        await RoleModel.increaseJewel(roleId, -1 * seqIds.length);
        return jewels;
    }

    public static async deleteAccount(roleId: string) {
        let result = await JewelModel.deleteMany({ roleId });
        return result;
    }

    private static getSearchObj(form: SearchJewelParam) {
        let searchObj = {};
        if(form.roleId) searchObj['roleId'] = form.roleId;
        if(form.roleName) searchObj['roleName'] = { $regex: new RegExp(form.roleName.toString(), 'i') };
        if(form.id) searchObj['id'] = form.id;
        return searchObj
      }
    
      public static async findByCondition(page: number, pageSize: number, sortField: string = 'updatedAt', sortOrder: string = 'descend', form: SearchJewelParam = {}) {
    
        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: JewelType[] = await JewelModel.find(searchObj).limit(pageSize).skip((page - 1) * pageSize).sort(sort).lean({ getters: true, virtuals: true });
        return result;
    
      }
    
      public static async countByCondition(form: SearchJewelParam = {}) {
    
          let searchObj = this.getSearchObj(form);
          const result = await JewelModel.count(searchObj);
          return result;
      }
}

export const JewelModel = getModelForClass(Jewel);

export interface JewelType extends Pick<DocumentType<Jewel>, keyof Jewel> {
    id: number;
};
export type jewelUpdate = Partial<JewelType>; // 将所有字段变成可选项