import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, modelOptions, ReturnModelType, mongoose } from '@typegoose/typegoose';
import { MARQUEE_SHOW_TYPE, MARQUEE_TIME_TYPE } from '../consts';
import { genCode } from '../pubUtils/util';
import { SearchMarqueeParam } from '../domain/backEndField/search';
import { nowSeconds } from '../pubUtils/timeUtil';

/**
  * 跑马灯
**/
class Receiver {
  @prop({ required: true })
  regionId: number;

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

  @prop({ required: true })
  serverId: number;
}

@modelOptions({ schemaOptions: { id: false } })
@index({ code: 1 })
export default class Marquee extends BaseModel {
  @prop({ required: true })
  code: string;                // 跑马灯唯一标识

  @prop({ required: true })
  receiverType: number;        // 推送目标

  @prop({ required: true, type: Receiver, _id: false })
  receivers: Receiver[];         // 推送服务器

  @prop({ required: true, enum: MARQUEE_TIME_TYPE })
  timeType: MARQUEE_TIME_TYPE;          // 推送时间类型，立刻/定时

  @prop({ required: true, enum: MARQUEE_SHOW_TYPE })
  showType: MARQUEE_SHOW_TYPE;          // 推送显示类型，一次性/循环

  @prop({ required: true, default: 0 })
  startTime: number;             // 循环开始时间/定时开始时间

  @prop({ required: true, default: 0 })
  endTime: number;               // 循环结束时间

  @prop({ required: true, default: 0 })
  interval: number;            // 推送间隔
  
  @prop({ required: true })
  content: string;             // 广播内容

  @prop({ required: true, default: true })
  isEnable: boolean;          // 当前正在发布

  setByForm(obj: any) {
    this.code = obj.code;
    this.receiverType = obj.receiverType;
    this.receivers = obj.receivers;
    this.timeType = obj.timeType;
    this.showType = obj.showType;
    if(this.timeType == MARQUEE_TIME_TYPE.INSTANT) {
      this.startTime = nowSeconds();
    } else {
      this.startTime = obj.startTime;
    }
    if(this.showType == MARQUEE_SHOW_TYPE.CIRCLE) {
      this.endTime = this.startTime + obj.continueMinute * 60;
      this.interval = obj.interval;
    }
    this.content = obj.content;
  }

  /**
   * 创建跑马灯
   * @param params 参数 
   * @param uid 后台操作人
   */
  public static async createData(params: MarqueeParam, uid = 1) {
    const code = genCode(6);
    const doc = new MarqueeModel();
    const update = Object.assign(doc.toJSON(), params, { code, createdBy: uid, updatedBy: uid });
    const result: MarqueeType = await MarqueeModel.findOneAndUpdate({ code }, { $setOnInsert: update }, { new: true, upsert: true }).lean();
    return result;
  }

  /**
   * 更新跑马灯
   * @param code 唯一标识 
   * @param params 参数
   * @param uid 后台操作人
   */
  public static async updateData(code: string, params: MarqueeParam, uid = 1) {
    const result: MarqueeType = await MarqueeModel.findOneAndUpdate({ code }, { $set: {...params, updatedBy: uid }}, { new: true }).lean();
    return result;
  }


  /**
   * 根据唯一code查询一条数据
   * @param {String} code 唯一码
   */
  public static async findByCode(code: string) {
    const result: MarqueeType = await MarqueeModel.findOne({ code }).lean();
    return result;
  }

  /**
   * 查询所有生效中的跑马灯
   */
  public static async findEffectiveMarque(env: string) {
    const result: MarqueeType[] = await MarqueeModel.find({ 
      $or: [
        { showType: MARQUEE_SHOW_TYPE.CIRCLE, startTime: { $lte: nowSeconds() }, endTime: { $gte: nowSeconds() }},
        { showType: MARQUEE_SHOW_TYPE.ONCE, startTime: { $lte: nowSeconds() }}
      ],
      isEnable: true,
      'receivers.env': env
    }).lean();
    return result;
  }


  private static getSearchObj(form: SearchMarqueeParam) {
    let searchObj = {};
    if(form.code) searchObj['code'] = form.code;
    if(form.createdBy) searchObj['createdBy'] = form.createdBy
    if(form.createTimeStart && form.createTimeEnd) {
      searchObj['createdAt'] = { $gt: new Date(form.createTimeStart * 1000), $lt: new Date(form.createTimeEnd * 1000) };
    }
    if(form.sendTimeStart && form.sendTimeEnd) {
      searchObj['startTime'] = { $gt: form.sendTimeStart, $lt: form.sendTimeEnd }
    }
    return searchObj
  }

  public static async findByCondition(page: number, pageSize: number, sortField: string = 'updatedAt', sortOrder: string = 'descend', form: SearchMarqueeParam = {}) {

    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: MarqueeType[] = await MarqueeModel.find(searchObj).limit(pageSize).skip((page - 1) * pageSize).sort(sort).lean({ getters: true, virtuals: true });
    return result;

  }

  public static async countByCondition(form: SearchMarqueeParam = {}) {

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


export let MarqueeModel: ReturnModelType<typeof Marquee, {}>;
export function loadMarqueeModel(connect: mongoose.Connection) {
  MarqueeModel = getModelForClass(Marquee, {
        existingConnection: connect
    });
}

export interface MarqueeType extends Pick<DocumentType<Marquee>, keyof Marquee> {};
export type MarqueeParam = Partial<MarqueeType>;
