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

export class RandSe {
    @prop({ required: true })
    id: number;					// 随机属性位置id
    @prop({ required: true })
    seid: number;					// 随机属性池id
    @prop({ required: true })
    rand: number;					// 随机属性内需要随机的值
    @prop({ required: true })
    locked: boolean;				// 洗炼是否锁定
}

export class Holes {
    @prop({ required: true })
    id: number;					  // 孔的id
    @prop({ required: true })
    isOpen: boolean;	  	// 是否开孔
    @prop({ required: true })
    jewel: number;				// 装备的宝石id
}

export class RandMain {
    @prop({ required: true })
    id: number;					// 随机属性位置id
    @prop({ required: true })
    rand: number;					// 随机属性内需要随机的值，扩大100倍
}

@index({ roleId: 1, hid: 1, id: 1 })
@index({ seqId: 1 })
@modelOptions({ schemaOptions: { id: false } })
export default class Equip 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, default: 1 })
    count: number;					// 装备数量

    @prop({ required: true, default: 1 })
    quality: number;				// 品质
    @prop({ required: true, default: 0 })
    suitId: number;					// 套装id

    @prop({ required: true, default: 0 })
    randRange: number;			    // 固定属性随机值   // TODO 废弃字段，客户端改完之前暂时保留
    @prop({ required: false, type: RandMain, default: [], _id: false })
    randMain: RandMain[];			// 主属性随机
    @prop({ required: true, default: 0 })
    grade: number;                  // 品相等级
    @prop({ required: false, type: RandSe, default: [], _id: false })
    randSe: RandSe[];				// 强化随机属性
    @prop({ required: true, type: Holes, default: [], _id: false })
    holes: Holes[];
    @prop({ required: false, type: RandSe, default: [], _id: false })
    previewRandSe: RandSe[];		// 强化随机属性预览


    public static async findbyRole(roleId: string, lean = true) {
        const equips: EquipType[] = await EquipModel.find({ roleId }).lean(lean);
        return equips;
    }

    public static async findbySeqId(seqId: number, select?: string ) {
        const equip: EquipType = await EquipModel.findOne({ seqId }).select(select).lean();
        return equip;
    }

    public static async createEquip(equipInfo: equipUpdate, lean = true) {
        const seqId = await CounterModel.getNewCounter(COUNTER.EID);

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

    public static async createEquips(roleId: string, equipInfos: equipUpdate[]) {
        let result: EquipType[] = [];
        for(let equipInfo of equipInfos) {
            let equip = await this.createEquip(equipInfo);
            result.push(equip);
        }
        await RoleModel.increaseEquip(roleId, result.length);
        return result;
    }

    public static async putOnOrOff(equipId: string, hid: number, lean = true) {
        const equip: EquipType = await EquipModel.findOneAndUpdate({ _id: equipId }, { hid }, { new: true }).lean(lean);
        return equip;
    }


    public static async findNotWearEquips(roleId: string) {
        const equips: EquipType[] = await EquipModel.find({ roleId, hid: 0 }).lean();
        return equips;
    }

    public static async deleteAccount(roleId: string) {
        let result = await EquipModel.deleteMany({ roleId });
        return result;
    }
    public static async deleteEquips(roleId: string, ids: Array<number>) {
        let result = await EquipModel.deleteMany({ roleId, seqId: { $in: ids } });
        await RoleModel.findOneAndUpdate({ roleId }, { $inc: { equipCount: -1 * ids.length } }, { new: true });
        return result;
    }

    public static async getEquipsByID(ids: Array<string>) {
        let result = await EquipModel.find({ _id: { $in: ids } });
        return result;
    }

    public static async getEquips(roleId: string, ids: Array<number>) {
        let result: EquipType[] = await EquipModel.find({ roleId, seqId: { $in: ids } });
        return result;
    }

    public static async getEquip(seqId: number) {
        let equip: EquipType = await EquipModel.findOne({ seqId });
        return equip;
    }

    public static async updateEquipInfo(seqId: number, equipUpdate: equipUpdate, lean = true) {
        delete equipUpdate._id;
        let result: EquipType = await EquipModel.findOneAndUpdate({ seqId }, { $set: equipUpdate }, { new: true }).lean(lean);
        return result;
    }

    public static async lock(roleId: string, seqId: number, id: number, lock: boolean) {
        let result: EquipType = await EquipModel.findOneAndUpdate({ roleId, seqId, 'randSe.id': id }, { $set: { 'randSe.$.locked': lock } }, { new: true, upsert: false }).select('seqId id randSe').lean();
        return result;
    }

    public static async updateEquipInfobyObjectId(_id: string, equipUpdate: equipUpdate, lean = true) {
        delete equipUpdate._id;
        let result: EquipType = await EquipModel.findOneAndUpdate({ _id }, { $set: equipUpdate }, { new: true }).lean(lean);
        return result;
    }

    public static async getEquipByObjectId(_id: string) {
        let equip: EquipType = await EquipModel.findOne({ _id });
        return equip;
    }


    public static async findByField(field: string, value?: number | string, select?: string) {
        let searchObj = {};
        if (field != 'all') {
            if (field == 'roleName') {
                searchObj['roleName'] = { $regex: new RegExp(value.toString(), 'i') }
            } else {
                searchObj[field] = value;
            }
        }
        //.select('uid tel username')
        const user: EquipType[] = await EquipModel.find(searchObj).select(select).lean();
        return user;
    }

    public static async findListByHidAndRole(roleId: string, hid: number, select?: string) {
        let result: EquipType[] = await EquipModel.find({ roleId, hid }).select(select).lean();
        return result;
    }

    public static async getEquipsByIds(roleId: string, ids: Array<number>) {
        let result = await EquipModel.find({ roleId, id: { $in: ids } });
        return result;
    }

}

export const EquipModel = getModelForClass(Equip);

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