import { BidRec } from './../domain/dbGeneral';
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose';
import { genCode } from '../pubUtils/util';
import { AUCTION_STAGE, BID_REC_COUNT, GUILD_LOTS_REC_COUNT, LOTS_KEEP_TO_WORLD_CNT, LOT_STATUS } from '../consts';

/**
  * 竞拍物品表
**/
@modelOptions({ schemaOptions: { id: false } })
@index({ sort: 1 })
@index({ seq: 1 })
@index({ code: 1 })
@index({ begin: -1 })
@index({ guildCode: 1, begin: -1 })
@index({ serverId: 1, begin: -1, watchingRoles: 1 })
export default class Lot extends BaseModel {
    @prop({ required: true, default: 0 })
    auctionStage: number; // 0：初始添加，1：军团拍卖，2：世界拍卖，3：拍卖结束
    @prop({ required: true, default: 0 })
    saveAuctionStage: number; // 0：初始添加，1：军团拍卖，2：世界拍卖，3：拍卖结束
    @prop({ required: true, default: 0 })
    sourceType: number; // 0：初始值，1：演武；2：蛮夷入侵；3：诸侯混战；4：粮草先行
    @prop({ required: true, default: '' })
    seq: number; // 当日的这个物品的编号
    @prop({ required: true, default: '' })
    sourceCode: string; // 来源的唯一标识，如活动编号
    @prop({ required: true, default: 0 })
    serverId: number; // 区服编号
    @prop({ required: true, default: '' })
    guildCode: string; // 军团编号
    @prop({ required: true, default: '' })
    code: string; // 竞拍物品唯一标识
    @prop({ required: true, default: 0 })
    gid: number; // 物品 id
    @prop({ required: true, default: 1 })
    count: number; // 物品数量
    @prop({ required: true, default: 0 })
    prePrice: number; // 当前出价
    @prop({ required: true, default: 0 })
    curPrice: number; // 当前出价
    @prop({ required: false, default: '' })
    curBuyer: string; // 当前出价最高者 RoleId
    @prop({ required: true, default: 0 })
    maxPrice: number; // 一口价，最高价格
    @prop({ required: true, type: BidRec, default: [] })
    bidRoles: BidRec[]; // 出价历史
    @prop({ required: true, type: String, default: [] })
    watchingRoles: string[]; // 正在关注的玩家
    @prop({ required: true })
    begin: Date; // 竞拍开始时间
    @prop({ required: true })
    end: Date; // 竞拍结束时间
    @prop({ required: true, default: 0 })
    status: number; // 拍品状态，0：无人竞拍；1：竞拍中；2：已竞拍；3：一口价
    @prop({ required: true, default: 0 })
    sort: number; // 排序
    @prop({ required: true, default: 0 })
    sendMail: boolean; // 是否是发邮件去的

    public static async createRec(data: LotParam) {
        const code = genCode(8);
        const docData = new LotModel();
        const result: LotType = await LotModel.findOneAndUpdate({ code }, { ...docData.toJSON(), ...data, code }, { upsert: true, new: true }).select('-_id').lean();
        return result;
    }

    public static async createRecs(datas: LotParam[]) {
        await LotModel.insertMany(datas);
        return <LotType[]>datas;
    }

    public static async findLot(code: string) {
        const result = await LotModel.findOne({ code }).select('-_id -__v').lean();
        return result;
    }

    public static async findLots(codes: string[]) {
        const result = await LotModel.find({ code: {$in: codes} }).sort({ sort: 1 }).select('-_id -__v').lean();
        return result;
    }

    public static async findGuildLotsByBegin(guildCode: string, begin: Date) {
        const results = await LotModel.find({ guildCode, begin, auctionStage: { $in: [AUCTION_STAGE.DEFAULT, AUCTION_STAGE.GUILD] } }).sort({ sort: 1 }).select('-_id -__v').lean();
        return results;
    }

    public static async findWorldLotsByBegin(serverId: number, begin: Date) {
        const results = await LotModel.find({ serverId, begin, auctionStage: AUCTION_STAGE.WORLD }).sort({ sort: 1 }).select('-_id -__v').lean();
        return results;
    }

    public static async findWatchingLotsByBegin(roleId: string, serverId: number, begin: Date) {
        const results = await LotModel.find({ serverId, begin, watchingRoles: roleId }, { new: true }).sort({ sort: 1 }).select('-_id -__v').lean();
        return results;
    }

    public static async recentGuildLots(guildCode: string, count = GUILD_LOTS_REC_COUNT ) {
        const results = await LotModel.find({ guildCode }).sort({ _id: -1 }).limit(count).sort({ sort: 1 }).select('-_id -__v').lean();
        return results;
    }

    public static async updateLot(data: LotParam) {
        const code = data.code!;
        if(data.status == LOT_STATUS.SOLD|| data.status == LOT_STATUS.MAX) {
            data.saveAuctionStage = data.auctionStage;
        }
        const result: LotType = await LotModel.findOneAndUpdate({ code }, { ...data }, { new: true }).select('-_id -__v').lean();
        return result;
    }

    public static async watchLot(code: string, roleId: string) {
        const result: LotType = await LotModel.findOneAndUpdate({ code }, { $addToSet: { watchingRoles: roleId } }, { new: true }).select('-_id -__v').lean();
        return result;
    }

    public static async unWatchLot(code: string, roleId: string) {
        const result: LotType = await LotModel.findOneAndUpdate({ code }, { $pull: { watchingRoles: roleId } }, { new: true }).select('-_id -__v').lean();
        return result;
    }

    public static async watchingLotsByBegin(serverId: number, roleId: string, begin: Date) {
        const results: LotType[] = await LotModel.find({ serverId, begin, watchingRoles: roleId }).sort({ sort: 1 }).select('-_id -__v').lean();
        return results;
    }

    public static async recentBidLots(serverId: number, roleId: string, count = BID_REC_COUNT) {
        const results: LotType[] = await LotModel.find({ serverId, 'bidRoles.roleId': roleId }).sort({ sort: 1 }).select('-_id -__v').sort({ _id: -1 }).limit(count).lean();
        return results;
    }

    public static async updateLotStage(code: string, auctionStage: number) {
        const result: LotType = await LotModel.findOneAndUpdate({ code }, { auctionStage }).select('-_id -__v').lean();
        return result;
    }

    public static async updateLotsStageByBegin(begin: Date, auctionStage: number) {
        await LotModel.updateMany({ begin }, { auctionStage });
        const results: LotType[] = await LotModel.find({ begin, auctionStage }).select('-_id -__v -createdAt -updatedAt').lean();
        return results;
    }

    public static async keepUnSoldLotsToWorld(begin: Date) {
        await LotModel.updateMany({ begin, status: { $in: [LOT_STATUS.DEFAULT, LOT_STATUS.ING] }, seq: { $gt: LOTS_KEEP_TO_WORLD_CNT } }, { status: LOT_STATUS.PASSIN });
        await LotModel.updateMany({ begin, status: { $in: [LOT_STATUS.DEFAULT, LOT_STATUS.ING] }, seq: { $lte: LOTS_KEEP_TO_WORLD_CNT, $gt: 0 } }, { $set: { auctionStage: AUCTION_STAGE.WORLD } });
        const results: LotType[] = await LotModel.find({ begin, status: { $in: [LOT_STATUS.DEFAULT, LOT_STATUS.ING] } }).select('-_id -__v').lean();
        return results;
    }

    public static async setLotSoldByBegin(begin: Date, saveAuctionStage: number) {
        await LotModel.updateMany({ begin, status: LOT_STATUS.ING }, { $set: { status: LOT_STATUS.SOLD, saveAuctionStage, sendMail: true } });
        const results: LotType[] = await LotModel.find({ begin, status: LOT_STATUS.SOLD, saveAuctionStage, sendMail: true }).sort({ sort: 1 }).select('-_id -__v').lean();
        return results;
    }

    public static async setSeq(begin: Date, gid: number, count: number, seq: number) {
        const results: LotType = await LotModel.findOneAndUpdate({ begin, gid, count, status: LOT_STATUS.DEFAULT }, { $set: { seq } }).sort({ seq: -1 }).select('-_id -__v').lean();
        return results;
    }
}

export const LotModel = getModelForClass(Lot);

export interface LotType extends Pick<DocumentType<Lot>, keyof Lot>{}
export type LotParam = Partial<LotType>;
