import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { gameData } from '../pubUtils/data';

export class WarStatus {
  @prop({ required: true })
  warId: number; // 策划表中战斗编号
  @prop({ required: false })
  battleCode?: string; // 服务器生成的战斗唯一标识
  @prop({ required: true })
  status: boolean; // 是否通过，true-通过，false-未通过
}

/**
  * 天梯记录表
  */
@index({ roleId: 1, lv: 1 })

export default class TowerRecord extends BaseModel {
  @prop({ required: true })
  roleId: string;					// 角色 id
  @prop({ required: true, default: 1 })
  lv: number;                       // 天梯层数
  @prop({ required: true, default: 0 })
  skipFrom: number;                       // 从哪层跳过来的天梯层数
  @prop({ required: true, default: [], type: Number })
  heroes: Array<number>;            // 本层已使用武将
  @prop({ required: true, type: WarStatus, default: [], _id: false })
  warStatus: Array<WarStatus>;
  @prop({ required: true, default: 0 })
  speedUpCnt: number;                       // 加速总次数
  @prop({ required: true, default: 0 })
  speedUpTime: number;                       // 加速总时长
  @prop({ required: true })
  hangUpTime: Date; // 挂机开始时间
  @prop({ required: true, default: false })
  passed: boolean; // 此层是否通过，true-通过，false-未通过

  public static async createRecord(towerInfo: {roleId: string, lv: number, warStatus: Array<WarStatus>}) {
    const recDoc = new TowerRecordModel();
    const update = Object.assign(recDoc.toJSON(), towerInfo );
    delete update._id;
    const { roleId, lv } = towerInfo;
    // console.log(JSON.stringify(towerInfo))
    let rec: TowerRecordType = await TowerRecordModel.findOneAndUpdate({roleId, lv}, {$set: update}, {upsert: true, new: true}).lean();
    return rec;
  }

  /**
   * 更新天梯记录
   * @param roleId 角色 Id
   * @param battleCode 服务器生成的战斗唯一标识
   * @param warId 策划表中的战斗 Id
   * @param heroes 使用的英雄列表
   * @param inc 升级的层数
   * @param lean 
   */
  public static async updateRecord(roleId: string, lv: number, battleCode: string, warId: number, heroes: Array<number>, inc: number, lean = true) {
    let tower = await TowerRecordModel.findOne({roleId, lv, 'warStatus.warId': warId});
    if(tower) {
      const rec: TowerRecordType = await TowerRecordModel.findOneAndUpdate(
        {roleId, lv, 'warStatus.warId': warId},
        {$set: {'warStatus.$.status': true, 'warStatus.$.battleCode': battleCode, passed: inc === 1 ? true : false}, $push: {heroes: {$each: heroes}}},
        {new: true, upsert: true}
      ).lean(lean);
      return rec;
    } else {
      let warStatus = [{warId, status: true,battleCode, passed: inc === 1 ? true : false}];
      const rec: TowerRecordType = await TowerRecordModel.findOneAndUpdate(
        {roleId, lv},
        { $push: {heroes: {$each: heroes}, warStatus: {$each: warStatus}}},
        {new: true, upsert: true}
      ).lean(lean);
      return rec;
    }
  }

  // 跳过当前层
  public static async skipTower(roleId: string, fromLv: number, curLv: number, warStatus: WarStatus[]) {
    // console.log('######## skipTower', roleId, fromLv, curLv)

    await TowerRecordModel.findOneAndUpdate({ roleId, lv: fromLv }, { $set: { passed: true } }, { new: true });

    const recDoc = new TowerRecordModel();
    const update = Object.assign(recDoc.toJSON(), { roleId, lv: curLv, skipFrom: fromLv, passed: true, warStatus } );
    delete update._id;

    let rec: TowerRecordType = await TowerRecordModel.findOneAndUpdate({ roleId, lv: curLv }, { $setOnInsert: update }, { new: true, upsert: true }).lean();
    return rec;
  }

  public static async getRecordByLv(roleId: string, lv: number, lean = true) {
    const rec: TowerRecordType = await TowerRecordModel.findOne({roleId, lv}).lean(lean);
    return rec;
  }

  public static async resetRecordByLv(roleId: string, lv: number, lean = true) {
    const rec: TowerRecordType = await TowerRecordModel.findOneAndUpdate(
      {roleId, lv, passed: false},
      {$set: {'warStatus.$[].status': false, 'warStatus.$[].battleCode': '', heroes: []}},
      {new: true}).lean(lean);
    return rec;
  }

  public static async insertTowerRec(roleId: string, lv: number) {
    let insertParams = [];
    let doc = new TowerRecordModel();
    for(let [towerLv, { warArray }] of gameData.tower) {
      if(towerLv < lv) {
        insertParams.push({...doc.toJSON(), roleId, lv: towerLv, warStatus: warArray.map(warId => ({ warId, status: true })), passed: true})
      } else if (towerLv == lv) {
        insertParams.push({...doc.toJSON(), roleId, lv: towerLv, warStatus: warArray.map(warId => ({ warId, status: true })), passed: false})
      }
    }
  }

  public static async deleteAccount(roleId: string) {
    let result = await TowerRecordModel.deleteMany({roleId});
    return result;
  }
}

export const TowerRecordModel = getModelForClass(TowerRecord);

export interface TowerRecordType extends Pick<DocumentType<TowerRecord>, keyof TowerRecord>{};