import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, Ref } from '@typegoose/typegoose';
import Role, { RoleType } from './Role';
import { GUILD_AUTH, USER_GUILD_STATUS, GUILD_JOB } from '../consts';
import { getZeroPointD, nowSeconds } from '../pubUtils/timeUtil';
import { ARMY } from '../pubUtils/dicParam';
class ActiveRecord {
    @prop({ required: true })
    id: number;
    @prop({ required: true })
    count: number;
}

class WishGood {
    @prop({ required: true })
    id: string;//随机生成的唯一id
    @prop({ required: true })
    type: number;//1：表示装备池，2：武将池
    @prop({ required: true })
    goodId: number;
    @prop({ required: true })
    count: number; //许愿次数
    @prop({ required: true, default:0 })
    receiveCnt: number; //收到次数
    @prop({ required: true, default:0 })
    drawCnt: number; //可以领取次数
    @prop({ required: true, type: String, default: [] })
    donateNames: string[];
}


@index({ roleId: 1 })
export default class UserGuild extends BaseModel {
    @prop({ required: true })
    guildCode: string;            

    @prop({ required: true })
    roleId: string;

    @prop({ required: true })
    role:  Ref<Role>;

    @prop({ required: true, default: GUILD_AUTH.MEMBER, enum: GUILD_AUTH })
    auth:  number;

    @prop({ required: true, default: GUILD_JOB.SHIBING, enum: GUILD_JOB })
    job: number;

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

    @prop({ required: true, default: 0 })
    activeDaily: number;
    
    @prop({ required: true, default: nowSeconds() })
    activeUpdateTime: number;

    @prop({ required: true, default: USER_GUILD_STATUS.ON, enum: USER_GUILD_STATUS})
    status: number;

    @prop({ required: true, type: ActiveRecord, default: [], _id: false })
    activeRecord: ActiveRecord[];

    @prop({ required: true, type: Number, default: [] })
    receivedActive: number[];

    @prop({ required: true, default: new Date(), select: false })
    refTimeDaily: Date;
    //练兵场
    @prop({ required: true, default: 0 })
    trainCount: number;//每日挑战训练场的次数

    @prop({ required: true, default: 0 })
    buyTrainCount: number;//每日挑战训练场购买次数

    @prop({ required: true, default: 0 })
    trainTime: number;//上次刷新挑战训练场次数的时间每天5点

    @prop({ required: true, default: [] })
    trainRewards: Array<number>;//领取过的进阶等级
    //捐献所
    @prop({ required: true, default: [], type: Number })
    receiveBoxs: Array<number>; //今天捐献所领取宝箱id记录，

    @prop({ required: true, default: 0 })
    donateCnt: number;//今天捐献所次数
    //许愿池
    @prop({ required: true, default: [], type: WishGood, _id: false })
    wishGoods: Array<WishGood>;

    @prop({ required: true, default: 0 })
    wishDntCnt: number;//今天许愿池捐献次数

    

    public static async getMyAuth(roleId: string, guildCode?: string, userGuild?: UserGuildType) {
        let myGuild: UserGuildType;
        if(!userGuild) {
            myGuild = await this.getMyGuild(roleId, 'auth');
        } else {
            myGuild = userGuild;
        }

        if(guildCode && userGuild && userGuild.guildCode != guildCode) {
            return GUILD_AUTH.OTHERS;
        }

        return myGuild?myGuild.auth: GUILD_AUTH.OTHERS;
    }

    public static async getMyGuild(roleId: string, select?: string) {

        const myGuild: UserGuildType = await UserGuildModel.findOne({ roleId, status: USER_GUILD_STATUS.ON })
        .select(select).lean();
        return myGuild;
    }

    public static async getListByGuild(guildCode: string, select?: string, sort: { auth?: number, activeWeekly?: number, activeUpdateTime?: number } = {auth: 1}) {
        const userGuilds: UserGuildType[] = await UserGuildModel.find({ guildCode, status: USER_GUILD_STATUS.ON })
        .select(select)
        .sort(sort)
        .populate('role', 'roleId roleName ce head frame spine lv title quitTime', 'Role')
        .lean({ getters: true, virtuals: true });
        return userGuilds;
    }

    public static async findTopActive(guildCode: string, select?: string) {
        const userGuilds: UserGuildType[] = await UserGuildModel.find({ guildCode, status: USER_GUILD_STATUS.ON, auth: { $ne: GUILD_AUTH.LEADER } })
        .sort({ activeWeekly: -1, activeUpdateTime: 1 })
        .select(select)
        .populate('role', 'roleId roleName ce head frame spine lv title quitTime', 'Role')
        .lean({getters: true, virtuals: true });
        return userGuilds;
    }

    public static async createUserGuild(guildCode: string, role: RoleType, isLeader: boolean) {
        const lastGuild = await UserGuildModel.findMyLastGuild(role.roleId);
        let { receiveBoxs = [], donateCnt = 0, receivedActive = [] } = lastGuild||{};

        const doc = new UserGuildModel();
        let job = isLeader? GUILD_JOB.DAJIANGJUN: GUILD_JOB.SHIBING;
        let auth = isLeader? GUILD_AUTH.LEADER: GUILD_AUTH.MEMBER;
        const update = Object.assign(doc.toJSON(), { guildCode, roleId: role.roleId, role: role._id, job, auth, receiveBoxs, donateCnt, receivedActive });
        delete update._id;
        const result: UserGuildType = await UserGuildModel.findOneAndUpdate({ roleId: role.roleId, guildCode, status: USER_GUILD_STATUS.ON }, update, { upsert: true, new: true })
        .select('activeDaily activeRecord activeWeekly activeUpdateTime job auth receivedActive')
        .lean();
        
        return result;
    }

    public static async findMyLastGuild(roleId: string) {
        const userGuild = await UserGuildModel.findOne({ roleId, status: { $ne: USER_GUILD_STATUS.ON } }).sort({ updatedAt: -1 }).lean();
        return userGuild;
    }

    public static async dismiss(guildCode: string) {
        const result = await UserGuildModel.updateMany({ guildCode }, { status: USER_GUILD_STATUS.DISMISSED });
        
        return result;
    }

    // 玩家退出公会
    public static async quit(guildCode: string, roleId: string) {
        const result = await UserGuildModel.findOneAndUpdate({ guildCode, roleId, status: USER_GUILD_STATUS.ON }, {status: USER_GUILD_STATUS.QUIT}, {new: true});
        return result;
    }

    public static async updateInfo(roleId: string, update: UserGuildUpdateParam, incParam: { activeDaily?: number, activeWeekly?: number, trainCount?: number }, select?: string) {
        const result: UserGuildType = await UserGuildModel.findOneAndUpdate({ roleId, status: USER_GUILD_STATUS.ON }, { $set: update, $inc: incParam }, { new: true }).select(select).lean();
        return result;
    }

    public static async receiveTrainRewards(roleId: string, trainId: number, lean = true) {
        const result = await UserGuildModel.findOneAndUpdate({ roleId, status: USER_GUILD_STATUS.ON}, 
            { $push:{trainRewards: trainId} },{new: true}).lean(lean);
        return result;
    }

    public static async addTrainCount(roleId: string, trainCount: number, lean = true) {
        const result = await UserGuildModel.findOneAndUpdate({ roleId, status: USER_GUILD_STATUS.ON}, 
            { $inc: { trainCount, buyTrainCount: trainCount } }, {new: true}).lean(lean);
        return result;
    }

    public static async resetTrainUserGuild(guildCode: string) {
        const result = await UserGuildModel.updateMany({ guildCode }, {$set: { trainCount: ARMY.ARMY_TRAIN_BUYTIMES, buyTrainCount: 0, trainTime: nowSeconds(), trainRewards: [] }});
        return result;
    }

    public static async donateFund(roleId: string, donateCnt: number, lean = true) {
        const result = await UserGuildModel.findOneAndUpdate({ roleId, status: USER_GUILD_STATUS.ON}, 
            {$inc: { donateCnt }}, {new: true}).lean(lean);
        return result;
    }

    public static async getWishPoolGoods(guildCode: string, select?: string, lean = true) {
        const userGuilds: UserGuildType[] = await UserGuildModel.find({ guildCode, status: USER_GUILD_STATUS.ON, refTimeDaily: { $gte: getZeroPointD() } })
        .select(select).lean(lean);
        return userGuilds;
    }

    public static async pushAndUpdate(roleId: string, update: UserGuildUpdateParam, pushData:{wishGoods?: WishGood}, select?: string) {
        const result: UserGuildType = await UserGuildModel.findOneAndUpdate({ roleId, status: USER_GUILD_STATUS.ON }, { $set: update, $push: pushData }, { new: true }).select(select).lean();
        return result;
    }

    public static async donateGoods(roleId: string, wishDntCnt: number, select?: string) {
        const result: UserGuildType = await UserGuildModel.findOneAndUpdate({ roleId, status: USER_GUILD_STATUS.ON }, { $inc: { wishDntCnt } }, { new: true }).select(select).lean();
        return result;
    }

    public static async donateUpdate(roleId: string, dntRoleName: string, id: string, select?: string) {
        const result: UserGuildType = await UserGuildModel.findOneAndUpdate({ roleId, status: USER_GUILD_STATUS.ON, 'wishGoods.id': id }, { $inc: { 'wishGoods.$.receiveCnt': 1,  'wishGoods.$.drawCnt': 1}, $push:{'wishGoods.$.dntRoleNames': dntRoleName} }, { new: true }).select(select).lean();
        return result;
    }
}

export const UserGuildModel = getModelForClass(UserGuild);

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