import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { TOWER_TASK_STATUS } from '../consts';
import { genCode } from '../pubUtils/util';
import { getZeroPointD } from '../pubUtils/timeUtil';
import { HeroType } from './Hero';
import { gameData } from '../pubUtils/data';

export class TaskHero {
  @prop({ required: true })
  seqId: number;
  @prop({ required: true })
  hid: number;
  @prop({ required: true })
  skinId: number;
  @prop({ required: true })
  jobClass: number;
  @prop({ required: true })
  star: number;
  @prop({ required: true })
  colorStar: number;
  @prop({ required: true })
  camp: number;
  
  constructor(hero: HeroType) {
    let dicHero = gameData.hero.get(hero.hid);
    this.seqId = hero.seqId;
    this.hid = hero.hid;
    this.skinId = hero.skinId;
    this.jobClass = dicHero.jobClass;
    this.star = hero.star;
    this.colorStar = hero.colorStar;
    this.camp = dicHero.camp;
  }
}

/**
  * 天梯派遣记录表
  */
@index({ roleId: 1, status: 1 })
@index({ batchCode: 1 })
@index({ taskCode: 1 })
@index({ createdAt: -1 })
export default class TowerTaskRec extends BaseModel {
  @prop({ required: true })
  roleId: string; // 角色 id
  @prop({ required: true })
  roleName: string; // 角色名

  @prop({ required: true })
  batchCode: string; // 本批派遣任务唯一标识
  @prop({ required: true })
  position: number; // 本批派遣任务当中的第几个任务
  @prop({ required: true, default: 0, enum: TOWER_TASK_STATUS })
  status: TOWER_TASK_STATUS; // 派遣任务当前状态，0-可派遣，1-已派遣，2-已完成，3-已领取
  @prop({ required: true, type: TaskHero, default: [], _id: false })
  heroes: TaskHero[]; // 此批派遣使用的全部武将

  @prop({ required: true })
  taskId: number; // 任务唯一 Id，来自任务表
  @prop({ required: true })
  taskCode: string; // 服务器生成的任务唯一编号
  @prop({ required: false })
  sendTime: Date; // 派遣时间
  @prop({ required: false })
  completeTime: Date; // 派遣结束时间

  public static async getCurTasks(roleId: string) {
    let today = getZeroPointD();
    const recs: TowerTaskRecType[] = await TowerTaskRecModel.find({ roleId, createdAt: { $gte: today } }).sort({ position: 1}).lean();
    return recs;
  }

  public static async getPreTasks(roleId: string) {
    let today = getZeroPointD();
    const recs: TowerTaskRecType[] = await TowerTaskRecModel.find({ roleId, createdAt: { $lt: today }, status: TOWER_TASK_STATUS.DOINING }).sort({ createdAt: -1, position: 1}).lean();
    return recs;
  }

  public static async getTaskByCode(roleId: string, taskCode: string) {
    let today = getZeroPointD();
    const recs: TowerTaskRecType = await TowerTaskRecModel.findOne({ roleId, taskCode, createdAt: { $gte: today } }).lean();
    return recs;
  }

  public static async createTasks(roleId: string, roleName: string, batchCode: string, taskIds: Array<number>) {
    const tasksData = taskIds.map((id, index) => {
      const taskModel = new TowerTaskRecModel();
      const taskCode = genCode(6);
      const taskData = Object.assign(taskModel.toJSON(), {batchCode, taskId: id, taskCode, roleId, roleName, position: index + 1 });
      return taskData;
    });
    const recs = await TowerTaskRecModel.insertMany(tasksData, {ordered: false});
    return recs;
  }

  public static async createTask(roleId: string, roleName: string, batchCode: string, taskId: number, position: number) {
    const taskModel = new TowerTaskRecModel();
    const taskCode = genCode(6);
    const taskData = Object.assign(taskModel.toJSON(), {batchCode, taskId, taskCode, roleId, roleName, position });
    delete taskData._id;

    const recs: TowerTaskRecType = await TowerTaskRecModel.findOneAndUpdate({ taskCode }, { $setOnInsert: taskData }, { new: true, upsert: true }).lean();
    return recs;
  }

  public static async updateTask(roleId: string, batchCode: string, position: number, taskId: number) {
    const recs: TowerTaskRecType = await TowerTaskRecModel.findOneAndUpdate({ roleId, batchCode, position, status: TOWER_TASK_STATUS.WAITING }, { $set: { taskId } }, { new: true }).lean();
    return recs;
  }

  public static async getTasksByCode(batchCode: string, lean = true) {
    const recs: TowerTaskRecType[] = await TowerTaskRecModel.find({batchCode}).lean(lean);
    return recs;
  }

  public static async sendHeroes(_roleId: string, batchCode: string, tasks: {taskCode:string, heroes: TaskHero[], completeTime: number}[], sendTime: Date, lean = true) {
    let recs = new Array();
    for (let {taskCode, heroes, completeTime} of tasks) {
      const rec: TowerTaskRecType = await TowerTaskRecModel.findOneAndUpdate(
        { batchCode, taskCode: taskCode },
        { heroes, status: TOWER_TASK_STATUS.DOINING, sendTime, completeTime: new Date(sendTime.getTime() + completeTime * 1000)},
        {new: true}).lean(lean);

      recs.push(rec);
    }
    return recs;
  }

  public static async finishTask(batchCode: string, tasks: Array<string>) {
    const recs:{ok: number, n:number, nModified:number} = await TowerTaskRecModel.updateMany({batchCode, taskCode: {$in:tasks}}, {status: 3, refreshStatus: -1});
    return recs;
  }

  // 将隐藏的任务显示出来 0=>1
  public static async showTask(roleId: string, batchCode: string, num: number, _lean = true) {
    const recs:{ok: number, n:number, nModified:number} = await TowerTaskRecModel.updateMany({roleId, refreshStatus: 0}, {batchCode, refreshStatus: 1}).sort({createdAt: 1}).limit(num);
    return recs;
  }
  // 刷掉旧任务 1=>-1
  public static async hideTask(roleId: string, taskIds: Array<string>, _lean = true) {
    // console.log(refTime)
    const recs:{ok: number, n:number, nModified:number} = await TowerTaskRecModel.updateMany({roleId, taskCode: {$in: taskIds}, refreshStatus: 1}, {refreshStatus: -1});
    return recs;
  }

  public static async updateBatchCode(roleId: string, taskIds: Array<string>, batchCode: string, _lean = true) {
    const recs:{ok: number, n:number, nModified:number} = await TowerTaskRecModel.updateMany({roleId, taskCode: {$in: taskIds}}, {batchCode});
    return recs;
  }

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

export const TowerTaskRecModel = getModelForClass(TowerTaskRec);

export interface TowerTaskRecType extends Pick<DocumentType<TowerTaskRec>, keyof TowerTaskRec>{};