import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { getFriendLvByExp } from '../pubUtils/data';
import * as util from '../pubUtils/friendUtil';
import { nowSeconds } from '../pubUtils/timeUtil';
import { FRIEND } from '../pubUtils/dicParam';
import { FRIEND_SELECT, FRIEND_SHIP_SELECT } from '../consts';

/**
  * 好友直接的亲密值
  */
@index({ roleIds: 1 })

export default class FriendShip extends BaseModel {

    @prop({ required: true, default: '' })
    roleIds: string;         // 玩家A和玩家B按字母顺排序后合成的字符串

    @prop({ required: true, default: '' })
    roleIdA: string;	    // 玩家A
    @prop({ required: true, default: '' })
    roleIdB: string;	    // 玩家B

    @prop({ required: true, default: 0 })
    sendHeartCntA: number;         // 玩家A给玩家B送的心
    @prop({ required: true, default: 0 })
    sendHeartCntATime: number;         // 玩家A给玩家B赠送时间

    @prop({ required: true, default: 0 })
    sendHeartCntB: number;         // 玩家B给玩家A送的心
    @prop({ required: true, default: 0 })
    sendHeartCntBTime: number;         // 玩家B给玩家A送的心赠送时间

    @prop({ required: true, default: 0 })
    receiveHeartCntA: number;      // 玩家B领取玩家A送的心
    @prop({ required: true, default: 0 })
    receiveHeartCntATime: number;      // 玩家B领取玩家A送的心时间

    @prop({ required: true, default: 0 })
    receiveHeartCntB: number;      // 玩家A领取玩家B送的心
    @prop({ required: true, default: 0 })
    receiveHeartCntBTime: number;      // 玩家A领取玩家B送的心时间

    @prop({ required: true, default: new Date() })
    refTime: Date;

    @prop({ required: true, default: 0 })
    friendValue: number;               // 两人之间的亲密值

    public get friendLv() {            // 亲密等级
        return getFriendLvByExp(this.friendValue);
    }

    // 创建
    public static async createFriendShip(roleIdList: string[]) {
        if (roleIdList.length != 2) return false;
        let { roleIdA, roleIdB, roleIds } = util.getRoleIds(roleIdList);

        const doc = new FriendShipModel();
        const update = Object.assign(doc.toJSON(), { roleIdA, roleIdB, roleIds });

        const result: FriendShipType = await FriendShipModel.findOneAndUpdate({ roleIds }, { $setOnInsert: update }, { upsert: true, new: true }).lean({ virtuals: true });

        return result;
    }

    // 清空亲密度
    public static async clearValue(roleIdList: string[]) {
        if (roleIdList.length != 2) return false;
        let { roleIds } = util.getRoleIds(roleIdList);

        const result: FriendShipType = await FriendShipModel.findOneAndUpdate({ roleIds }, { $set: { friendValue: 0 } }, { new: true }).lean({ virtuals: true });
        return result;
    }

    // 查询关系
    public static async deleteAccount(roleId: string) {
        let result = await FriendShipModel.deleteMany({ $or: [{ roleIdA: roleId }, { roleIdB: roleId }] });
        return result;
    }

    public static async refreshSendAndReceive(roleId: string, hisRoleId: string) {
        let { roleIds } = util.getRoleIds([roleId, hisRoleId]);
        let obj = this.getRefData();
        const result: FriendShipType = await FriendShipModel.findOneAndUpdate({ roleIds }, { 
            $set: { ...obj  } 
        }, { new: true }).lean({ virtuals: true });
        return result;
    }

    private static getRefData() {
        return {
            sendHeartCntA: 0, sendHeartCntB: 0, receiveHeartCntA: 0, receiveHeartCntB: 0, refTime: new Date()
        }
    }

    // 赠送爱心
    public static async sendHeart(roleId: string, hisRoleId: string, inc: number, max: number, shouldRefresh: boolean) {
        let { roleIds } = util.getRoleIds([roleId, hisRoleId]);
        let params = util.inputSendCnt(roleId, hisRoleId, { 
            inc: { sendHeart: inc }, 
            set: { sendHeartTime: nowSeconds() },
            lt: { sendHeart: max - inc }
        });
        // console.log(JSON.stringify(params))
        if (!params) return false;
        let result: FriendShipType;
        if(shouldRefresh) {
            let obj = this.getRefData();
            result = await FriendShipModel.findOneAndUpdate({ roleIds }, {
                $inc: { friendValue: FRIEND.FRIEND_CLOSEPOINT_ADD}, 
                $set: { ...obj, ...params.inc, ...params.set }
            }, { new: true }).lean({ virtuals: true });
        } else {
            result = await FriendShipModel.findOneAndUpdate({ roleIds, ...params.lt }, {
                $inc: { ...params.inc, friendValue: FRIEND.FRIEND_CLOSEPOINT_ADD}, 
                $set: params.set
            }, { new: true }).lean({ virtuals: true });
        }
        return result;
    }

    // 领取爱心
    public static async receiveHeart(roleId: string, hisRoleId: string, inc: number, max: number, shouldRefresh: boolean) {
        let { roleIds } = util.getRoleIds([roleId, hisRoleId]);
        let params = util.inputReceiveCnt(roleId, hisRoleId, { 
            inc: { receiveHeart: inc }, 
            set: { receiveHeartTime: nowSeconds() },
            lt: { receiveHeart: max - inc }
        });
        if (!params) return false;

        let result: FriendShipType;
        if(shouldRefresh) {
            let obj = this.getRefData();
            result = await FriendShipModel.findOneAndUpdate({ roleIds }, {
                $inc: { friendValue: 5}, 
                $set: { ...obj, ...params.inc, ...params.set }
            }, { new: true }).lean({ virtuals: true });
        } else {
            result = await FriendShipModel.findOneAndUpdate({ roleIds, ...params.lt }, {
                $inc: { ...params.inc, friendValue: 5}, 
                $set: params.set
            }, { new: true }).lean({ virtuals: true });
        }

        return result;
    }

    // 增加亲密度
    public static async addFriendValue(roleId: string, hisRoleId: string, inc: number) {
        let { roleIds } = util.getRoleIds([roleId, hisRoleId]);
        let result: FriendShipType = await FriendShipModel.findOneAndUpdate({ roleIds }, { $inc: { friendValue: inc } }, { new: true })
            .select(FRIEND_SELECT.SEND_PRESENT)
            .lean({ virtuals: true });
        return result;
    }

    public static async getFriendLv(roleId: string, hisRoleId: string) {
        let { roleIds } = util.getRoleIds([roleId, hisRoleId]);

        let result: FriendShipType = await FriendShipModel.findOne({ roleIds }).select(FRIEND_SHIP_SELECT.GET_FRIEND_VALUE).lean({ virtuals: true });
        return result;
    }
}

export const FriendShipModel = getModelForClass(FriendShip);

export interface FriendShipType extends Pick<DocumentType<FriendShip>, keyof FriendShip> { };