import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose';
import { GameModel } from './Game';
import { CounterModel } from './Counter';
import { COUNTER, SERVER_STATUS } from '../consts';
import { ServerStategyTypeParam } from './ServerStategy';
import { getServerName, getServerGroupName } from '../pubUtils/data';

// 暂时服务器列表是从game表取的，之后会转移到使用这张表，目前用作查询该服战力中位数

/**
  * 游戏字段接口
*/
@index({ id: 1 })
@modelOptions({ schemaOptions: { id: false } })
export default class Serverlist extends BaseModel {

  @prop({ required: true, default: 1 })
  gameId: number;            // 游戏id Game表的id

  @prop({ required: true })
  id: number;                // 小区id 自增

  @prop({ required: true })
  serverId: number;              // 相同serverType下的id，不同serverType下id一定不同，但是serverId可能相同

  @prop({ required: true })
  name: string;              // 小区区名

  @prop({ required: true })
  groupId: number;           // 大区id

  @prop({ required: true })
  groupName: string;          // 大区区名

  @prop({ required: true })
  host: string;               // pinus连接地址

  @prop({ required: false, default: 3014 })
  port: number;               // pinus端口

  @prop({ required: true, default: 1, enum: SERVER_STATUS })
  serverStatus: number;       // 服务器状态

  @prop({ required: true, type: Number })
  activityGroupId: number[];  // 活动组

  public get status() {
    let now = new Date();
    if (now > this.openTime) {
      return this.serverStatus;
    } else {
      return SERVER_STATUS.WILL_OPEN; // 未开服
    }
  }

  @prop({ required: true })
  openTime: Date;

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

  @prop({ required: true, default: 0 })
  maxPlayerCnt: number;          // 最大玩家人数

  @prop({ required: true, default: 0 })
  medianCe: number;          // 中位数武将战力、缩小10000倍后的结果

  public static async getAllServerList() {
    let servers: ServerlistType[] = await ServerlistModel.find().lean({ getters: true, virtuals: true });
    return servers;
  }

  public static async findByServerId(serverId: number) {
    let server: ServerlistType = await ServerlistModel.findOne({ id: serverId }).select('medianCe activityGroupId').lean({ getters: true, virtuals: true });
    return server;
  }

  public static async updateByServerId(serverId: number, update: ServerlistUpdate) {
    let server: ServerlistType = await ServerlistModel.findOneAndUpdate({ id: serverId }, { $set: update }).lean({ getters: true, virtuals: true });
    return server;
  }

  public static async updateByServerIds(serverIds: number[], update: ServerlistUpdate) {
    const result = await ServerlistModel.updateMany({ id: { $in: serverIds } }, { $set: update });
    return result;
  }

  public static async updateGroupName(groupId: number, groupName: string) {
    let server = await ServerlistModel.updateMany({ groupId }, { $set: { groupName } });
    return server;
  }

  public static async newServer(params: { serverType: string, openTime: Date, name?: string }, stategy: ServerStategyTypeParam, uid = 1 ) {
    let { serverType, name } = params;

    let serverEnvs = await GameModel.getServerEnvList();
    let curEnv = serverEnvs.find(cur => cur.serverType == serverType);
    if(!curEnv) return false;
    let { gameHost: host } = curEnv;

    // 分大区
    let groupId = await CounterModel.getCounter(COUNTER.SERVER_GROUP);
    let groupServerCount = await ServerlistModel.countByCondition({ serverType, groupId });
    if(groupServerCount > 10) {
      groupId = await CounterModel.getNewCounter(COUNTER.SERVER_GROUP);
    }
    let groupName = getServerGroupName(groupId)||"";

    let serverId = await CounterModel.getNewCounter({ name: `${COUNTER.SERVER_BY_TYPE.name}_${serverType}`, def: COUNTER.SERVER_BY_TYPE.def });
    let id = await CounterModel.getNewCounter(COUNTER.SERVER);
    if(!name) name = getServerName(id)||"";

    const doc = new ServerlistModel();
    const update = Object.assign(doc.toJSON(), params, { id, serverId, host, groupId, groupName, name, createdBy: uid, updatedBy: uid }, { activityGroupId: stategy.activityGroupId, maxPlayerCnt: stategy.maxPlayerCnt});

    let server: ServerlistType = await ServerlistModel.findOneAndUpdate({ id }, { $setOnInsert: update }, { new: true, upsert: true }).lean({ getters: true, virtuals: true });
    return server;
  }

  public static async findByServerType(serverType?: string) {
    let condition = {};
    if(serverType) {
      condition['serverType'] = serverType;
    }
    let server: ServerlistType[] = await ServerlistModel.find(condition).sort({ id: -1 }).lean({ getters: true, virtuals: true });
    return server;
  }

  private static getSearchObj(form: { id?: number, serverId?: string|number, name?: string, groupName?: string, groupId?: number, serverType?: string }) {
    let searchObj = {};
    if (form.id != undefined) searchObj['id'] = form.id;
    if (form.serverId != undefined) searchObj['serverId'] = form.serverId;
    if (form.groupId != undefined) searchObj['groupId'] = form.groupId;
    if (form.name != undefined) searchObj['name'] = { $regex: new RegExp(form.name.toString(), 'i') };
    if (form.groupName != undefined) searchObj['groupName'] = { $regex: new RegExp(form.groupName.toString(), 'i') };
    if (form.serverType != undefined) searchObj['serverType'] = form.serverType;
    return searchObj
  }

  public static async findByCondition(page: number, pageSize: number, sortField: string, sortOrder: string, form: { id?: number, serverId?: string|number, name?: string, groupName?: string, groupId?: number, serverType?: string } = {}) {

    let searchObj = this.getSearchObj(form);
    let sort = {};
    if(sortField && sortOrder) {
        if(sortOrder == 'ascend') {
            sort[sortField] = 1;
        } else if (sortOrder == 'descend') {
            sort[sortField] = -1;
        }
    }
    const result: ServerlistType[] = await ServerlistModel.find(searchObj, { _id: 0 }).limit(pageSize).skip((page - 1) * pageSize).sort(sort).lean({ getters: true, virtuals: true });
    return result;

  }

  public static async countByCondition(form: { id?: number, serverId?: string|number, name?: string, groupName?: string, groupId?: number, serverType?: string } = {}) {

    let searchObj = this.getSearchObj(form);
    const result = await ServerlistModel.count(searchObj);
    return result;
  }

  //根据多个活动id查询活动数据
  public static async findServerByIds(ids: number[]) {
    let result: ServerlistType[] = await ServerlistModel.find({ id: { $in: ids } }).lean();
    return result;
  }

  public static async updateActivityGroup(id: string, pushArr: number[], pullArr: number[]) {
    // console.log(id, pushArr, pullArr)
    let update = {};
    if(pushArr.length > 0) update['$push'] = { activityGroupId: { $each: pushArr } };
    if(pullArr.length > 0) update['$pull'] = { activityGroupId: { $in: pullArr } };
    let result: ServerlistType[] = await ServerlistModel.findOneAndUpdate({ _id: id }, update).lean();
    return result;
  }

  public static async pullByGroupId(groupId: number) {
    let result = await ServerlistModel.updateMany({ activityGroupId: { $elemMatch: { $eq: groupId } }}, { $pull: { activityGroupId: groupId } }, { new: true }).lean(true);
    return result;
  }

}

export const ServerlistModel = getModelForClass(Serverlist);

export interface ServerlistType extends Pick<DocumentType<Serverlist>, keyof Serverlist> {
  id: number;
};
export type ServerlistUpdate = Partial<ServerlistType>; // 将所有字段变成可选项
