import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose';
import { getZeroPointD } from '../pubUtils/timeUtil';
import { RECRUIT } from '../pubUtils/dicParam';
import { Candidate, SimpleResult } from '../domain/activityField/guideGachaField';

export class Floor {
  @prop({ required: true })
  id: number;            // 保底类型 1-紫将保底 2-金将保底 3-指定将保底
  @prop({ required: true })
  count: number;         // 抽卡次数
  @prop({ required: true })
  hasGetFloor: boolean;  // 是否抽到保底了
}

/**
* @description 心愿单
* @memberof UserGacha
*/
class Hope {
  @prop({ required: true })
  id: number;            // 位置
  @prop({ required: true })
  hid: number;          // 武将id
  @prop({ required: true })
  hasGet: boolean;       // 是否得到
}

/**
* @description 转盘记录
* @memberof UserGacha
*/
class Turntable {
  @prop({ required: true })
  quality: number;       // 品质
  @prop({ required: true })
  hasGet: boolean;       // 是否得到
}

/**
  * 玩家抽卡表
**/
@modelOptions({ schemaOptions: { id: false } })
@index({ roleId: 1, gachaId: 1 })

export default class UserGacha extends BaseModel {

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

    @prop({ required: true })
    gachaId: number;			    // 抽卡id 1-元宝 2-友情 3-指定 4-限时

    @prop({ required: true, default: 0 })
    activityId: number;			        // 限时抽卡对应活动id

    @prop({ required: true, default: 0 })
    count: number;			      // 已抽卡次数

    @prop({ required: true, type: Floor, default: [], _id: false })
    floor: Floor[];           // 已抽卡次数

    @prop({ required: true, default: 0 })
    freeCount: number;		    // 免费次数

    @prop({ required: true, default: getZeroPointD })
    refFreeTime: Date;		    // 免费次数刷新时间

    @prop({ required: true, type: () => Hope, default: [], _id: false })
    hope: Hope[];             // 心愿单

    @prop({ required: true, default: getZeroPointD })
    refHopeTime: Date;		    // 心愿单刷新时间

    @prop({ required: true, default: 0 })
    costPoint: number;            // 消耗的积分

    // 积分
    public get point() {
      return Math.floor(this.count/RECRUIT.RECRUIT_BONUS) - (this.costPoint||0);
    }

    @prop({ required: true, type: Turntable, default: [], _id: false })
    turntable: Turntable[];             // 转盘

    @prop({ required: true, default: 0 })
    pickHero: number;            // 玩家指定武将

    @prop({ required: true, default: [], type: Number })
    visitedHero: number[];            // 玩家指定武将

    @prop({ required: true, default: getZeroPointD  })
    refVisitedTime: Date;            // 玩家指定武将

    // 初始特殊引导
    @prop({ required: true, default: 0 })
    pullCnt: number;            // 预抽卡次数

    @prop({ required: true, type: () => SimpleResult, default: [], _id: false })
    guideResultList: SimpleResult[];            // 预抽卡结果

    @prop({ required: true, type: () => Candidate, default: [], _id: false })
    candidates: Candidate[];            // 预抽卡候选

    public static async findAllByRole(roleId: string) {
      let rec: UserGachaType[] = await UserGachaModel.find({ roleId }).lean({ virtuals: true });
      return rec;
    }

    public static async findByRole(roleId: string, gachaId: number, activityId: number) {
      const doc = new UserGachaModel();
      const update = Object.assign(doc.toJSON(), { roleId, gachaId, activityId });
      delete update._id;
      let rec: UserGachaType = await UserGachaModel.findOneAndUpdate({ roleId, gachaId, activityId }, { $setOnInsert: update }, { new: true, upsert: true }).lean({ virtuals: true });
      return rec;
    }

    public static async updateInfo(roleId: string, gachaId: number, activityId: number, update: UserGachaParam, inc: { pullCnt?: number, count?: number } = {}) {
      const doc = new UserGachaModel();
      const setOnInsert = doc.toJSON();
      delete setOnInsert._id;
      for(let key in update) {
        delete setOnInsert[key];
      }
      for(let key in inc) {
        delete setOnInsert[key];
      }
      let rec: UserGachaType = await UserGachaModel.findOneAndUpdate({ roleId, gachaId, activityId }, { $set: update, $setOnInsert: setOnInsert, $inc: inc }, { new: true, upsert: true }).lean({ virtuals: true });
      return rec;
    }

    public static async refreshFreeCount(roleId: string, gachaId: number, activityId: number, refFreeTime: Date) {
      let rec: UserGachaType = await UserGachaModel.findOneAndUpdate({ roleId, gachaId, activityId }, { $set: { freeCount: 0, refFreeTime } }, { new: true }).lean({ virtuals: true });
      return rec;
    }

    public static async refreshHopeCount(roleId: string, gachaId: number, activityId: number, hope: Hope[], refHopeTime: Date) {
      let rec: UserGachaType = await UserGachaModel.findOneAndUpdate({ roleId, gachaId, activityId }, { $set: { hope, refHopeTime } }, { new: true }).lean({ virtuals: true });
      return rec;
    }
}

export const UserGachaModel = getModelForClass(UserGacha);

export interface UserGachaType extends Pick<DocumentType<UserGacha>, keyof UserGacha> { }
export type UserGachaParam = Partial<UserGachaType>;
