import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { DAY_TO_SECOND, getZeroPoint } from '../pubUtils/timeUtil';

@index({ day: 1, groupKey: 1, score: 1 })
@index({ leagueCode: 1 })
export default class GVGVestigeLeagueRank extends BaseModel {

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

    @prop({ required: true })
    day: number;           // 每天5点

    @prop({ required: true })
    leagueCode: string;       // 玩家id

    @prop({ required: true })
    groupKey: string;    // 1-单服 2-跨服

    @prop({ required: true })
    score: number;          // 得分

    @prop({ required: true })
    rank: number;          // 最后的排名，每天22点定格

    @prop({ required: true, type: String })
    receiveMembers: string[];   // 是否领取过

    public static async incScore(configId: number, leagueCode: string, groupKey: string, inc: number) {
        let today = getZeroPoint();
        let result: GVGVestigeLeagueRankType = await GVGVestigeLeagueRankModel.findOneAndUpdate({ 
             day: today, groupKey, leagueCode
         }, { $inc: { score: inc }, $set: { configId }, $setOnInsert: { rank: 0, receiveMembers: [] } }, { new: true, upsert: true }).lean();
        return result;
    }

    // 排行榜
    public static async findRank(): Promise<{ _id: string, arr: { leagueCode: string, score: number, updatedAt: Date }[], leagueCodes: string[] }[]> {
        let today = getZeroPoint();
        let ranks = await GVGVestigeLeagueRankModel.aggregate([
            { $match: { day: today } },
            { $group: { 
                _id: "$groupKey", 
                arr: { $push: { leagueCode: "$leagueCode", score: "$score", updatedAt: "$updatedAt" } }, leagueCodes: { $addToSet: "$leagueCode" }
            }},
        ]);
        return ranks;
    }

    public static async saveRank(groupKey: string, ranks: { rank: number, field: string }[]) {
        let today = getZeroPoint();
        await GVGVestigeLeagueRankModel.bulkWrite(ranks.map(({ field, rank }) => {
            return { updateOne: { filter: { day: today, groupKey, leagueCode: field }, update: { $set: { rank } }} }
        }));
    }

    public static async getYesterdayRank(leagueCode: string) {
        let yesterday = getZeroPoint() - DAY_TO_SECOND;
        let result: GVGVestigeLeagueRankType = await GVGVestigeLeagueRankModel.findOne({ day: yesterday, leagueCode }).lean();
        return result;
    }

    public static async getCanReceiveRanks(configId: number, leagueCode: string, roleId: string) {
        let result: GVGVestigeLeagueRankType[] = await GVGVestigeLeagueRankModel.find({ configId, leagueCode, rank: { $gt: 0 }, receiveMembers: { $nin: [roleId] } }).lean();
        return result;
    }

    public static async receiveRanks(_ids: string[], roleId: string) {
        await GVGVestigeLeagueRankModel.updateMany({ _id: { $in: _ids } }, { $push: { receiveMembers: roleId } });
    }

    public static async receiveManyRanks(arr: { _id: string, roleIds: string[]}[]) {
        await GVGVestigeLeagueRankModel.bulkWrite(arr.map(({ _id, roleIds}) => {
            return { updateOne: { filter: { _id }, update: { $push: { receiveMembers: roleIds } } } }
        }));
    }

    public static async getAllCanReceiveRanks(configId: number, leagueCodes: string[]) {
        let result: GVGVestigeLeagueRankType[] = await GVGVestigeLeagueRankModel.find({ configId, rank: { $gt: 0 }, leagueCode: { $in: leagueCodes } }).lean();
        return result;
    }
}

export const GVGVestigeLeagueRankModel = getModelForClass(GVGVestigeLeagueRank);

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