import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, } from '@typegoose/typegoose';
import { LEAGUE_JOB } from '../consts';
import { GVG } from '../pubUtils/dicParam';

export class Tech {
    @prop({ required: true, default: 0 })
    id: number;
    @prop({ required: true, default: 0 })
    progress: number;  // 贡献
    @prop({ required: true, default: 0 })
    maxProgress: number;  // 贡献

    constructor(id: number, maxProgress: number) {
        this.id = id;
        this.progress = 0;
        this.maxProgress = maxProgress;
    }
}

class DonateRec {
    @prop({ required: true, default: 0 })
    roleId: string;
    @prop({ required: true, default: 0 })
    time: number;
    @prop({ required: true, default: 0 })
    count: number;
}

class Resource {
    @prop({ required: true, default: 0 })
    food: number;        // 粮食
    @prop({ required: true, default: 0 })
    mineral: number;     // 矿物
    @prop({ required: true, default: 0 })
    wood: number;        // 木堆
}

class GuildActive {
    @prop({ required: true, default: '' })
    guildCode: string;        // 军团
    @prop({ required: true, default: 0 })
    active: number;
}

@index({ leagueCode: 1, configId: 1 })
@index({ configId: 1, lv: -1 })
export default class GVGLeaguePrepare extends BaseModel {

    @prop({ required: true })
    configId: number;       // 赛期配置id

    @prop({ required: true })
    groupKey: string;       // 战区

    @prop({ required: true })
    leagueCode: string;     // 联军

    @prop({ required: true, default: 1 })
    lv: number;                  // 等级

    @prop({ required: true, default: 0 })
    maxMemberCnt: number;          // 进入备战期初始玩家人数

    @prop({ required: true, default: 0 })
    producerCnt: number;         // 选择内政人数

    @prop({ required: true, default: 0 })
    fighterCnt: number;         // 选择外政人数

    @prop({ required: true, default: [], type: Number, _id: false })
    activeTech: number[];             // 已激活完了的

    @prop({ required: true, default: [], type: Tech, _id: false })
    techQueue: Tech[];             // 千机阁

    @prop({ required: true, default: 0 })
    techQueueCnt: number;             // 千机阁队列数量

    @prop({ required: true, default: [], type: DonateRec, _id: false })
    donateRec: DonateRec[];      // 捐献记录

    @prop({ required: true, default: {food: 0, mineral: 0, wood: 0}, type: Resource, _id: false })
    resources: Resource

    @prop({ required: true, default: [], type: GuildActive, _id: false })
    guildActive: GuildActive[];             // 军团活跃

    public static async initData(configId: number, groupKey: string, leagueCode: string, maxMemberCnt: number) {
        const doc = new GVGLeaguePrepareModel();
        const update = Object.assign(doc.toJSON(), { maxMemberCnt });
        delete update._id;

        const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode, groupKey }, { $setOnInsert: update }, { upsert: true, new: true })
        .select({ _id: 0, __v: 0, createdAt: 0, updatedAt: 0 }).lean();
        return result;
    }

    public static async findByLeague(configId: number, leagueCode: string) {
        const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOne({ configId, leagueCode }).lean();
        return result;
    }


    public static async findByLeagueCodes(configId: number, leagueCodes: string[]) {
        const result: GVGLeaguePrepareType[] = await GVGLeaguePrepareModel.findOne({ configId, leagueCode: { $in: leagueCodes } }).lean();
        return result;
    }

    public static async chooseJob(configId: number, leagueCode: string, job: LEAGUE_JOB) {
        if(job == LEAGUE_JOB.FIGHTER) {
            const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode }, { $inc: { fighterCnt: 1 } }, { new: true }).lean();
            return result;
        } else {
            const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode }, { $inc: { producerCnt: 1 } }, { new: true }).lean();
            return result;
        }
    }

    public static async unlockTech(configId: number, leagueCode: string, techId: number, maxProgress: number) {
        const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ 
            configId, leagueCode, techQueueCnt: { $lt: GVG.GVG_LEAGUE_TECH_LIST } 
        }, { $push: { techQueue: new Tech(techId, maxProgress) }, $inc: { techQueueCnt: 1 } }, { new: true }).lean();
        return result;
    }

    public static async addProgress(configId: number, leagueCode: string, techId: number, addProgress: number) {
        const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ 
            configId, leagueCode, 'techQueue.id': techId 
        }, { $inc: { 'techQueue.$.progress': addProgress } }, { new: true }).lean();
        return result;
    }

    public static async activate(configId: number, leagueCode: string, techId: number) {
        const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ 
            configId, leagueCode 
        }, { $push: { activeTech: techId},  $pull: { techQueue: { id: techId } }, $inc: { techQueueCnt: -1 } }, { new: true }).lean();
        return result;
    }

    public static async addResource(configId: number, leagueCode: string, food: number, mineral: number, wood: number) {
        const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ 
            configId, leagueCode
        }, { 
            $inc: { 'resources.food': food, 'resources.mineral': mineral, 'resources.wood': wood }
        }, { new: true }).lean();
        return result;
    }

    public static async setLv(configId: number, leagueCode: string, lv: number) {
        const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode }, { $set: { lv }}, { new: true }).lean();
        return result;
    }

    public static async findByConfigId(configId: number) {
        const result: GVGLeaguePrepareType[] = await GVGLeaguePrepareModel.aggregate([{ $match: {configId} }]);
        return result;
    }

    public static async getLvRank(configId: number) {
        const result: GVGLeaguePrepareType[] = await GVGLeaguePrepareModel.find({ configId }).sort({ lv: -1 }).lean();
        return result;
    }
}

export const GVGLeaguePrepareModel = getModelForClass(GVGLeaguePrepare);

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