import {OptionalId, UpdateFilter, UpdateOptions} from 'mongodb';
import {CollectionGongHui} from '../../module/collection_gonghui';
import {MongodbCollections} from '../../module/mongodb';
import {ReqChange} from '../../shared/protocols/gonghui/PtlChange';
import {gonghuiLevel} from '../../shared/protocols/gonghui/type';
import {player} from '../../shared/protocols/user/type';
import {EmailFun} from '../email';
import {PlayerFun} from '../player';
import {GongHuiFun} from './gonghui';
import {GHManage} from './manage';
import {PublicShared} from "../../shared/public/public";
import { getGud } from '../gud';

export class GH {
    /**当前是否有人在挑战boss */
    isFightBoss: boolean;

    get maxPlayerNum() {
        return G.gc.shili_lv[this.data.lv].maxNum;
    }

    constructor(public data: CollectionGongHui) {
        if (!data.fuben) {
            data.fuben = {
                id: '1',
                dps: {},
                bossInfo: {}
            };
            this.updateDb({$set: {fuben: data.fuben}});
        }
    }

    /**更改isFightBoss状态 */
    async changeIsFightBoss(bool = false) {
        const key = 'gonghui:isFightBoss:' + this.data._id;
        if (bool) {
            await G.ioredis.setnx(key, 1);
            await G.ioredis.expire(key, 1);
        } else {
            await G.ioredis.del(key);
        }
        return
    }

    /**获取isFightBoss状态 */
    async getIsFightBoss(): Promise<boolean> {
        const key = 'gonghui:isFightBoss:' + this.data._id;
        return await G.ioredis.get(key)? true : false;
    }

    /**
     * 更新redis数据
     */
    updateRedis() {
        GHManage.setGH(this.data._id, this.data);
    }

    /**
     * 更新数据库
     */
    async updateDb(update: UpdateFilter<OptionalId<MongodbCollections['gonghui']>>, options: UpdateOptions = {}) {
        let keys = Object.values(update).map(obj => Object.keys(obj).map(key => key.split('.')[0])).reduce((a, b) => a.concat(b));
        let change = Object.fromEntries(keys.map(key => [key, this.data[key]]));
        this.data.players.forEach(p => G.server.sendMsgByUid(p.uid, 'msg_s2c/GhChange', change));
        this.updateRedis();
        return await G.mongodb.collection('gonghui').updateOne({_id: G.mongodb.conversionId(this.data._id)}, update, options);
    }

    /**
     * 更新会长名字
     */
    async updateCreateName(name: string) {
        this.data.createPlayer.name = name;
        this.updateRedis();
        GongHuiFun.db.updateOne({_id: G.mongodb.conversionId(this.data._id)}, {$set: {'createPlayer.name': name}});
    }

    /**
     * 更新公会设置
     */
    async updateSetting(change: ReqChange) {
        if (change.name) {
            this.data.name = change.name;
            this.updateDb({$set: {name: this.data.name}});

            this.data.players.forEach(player => {
                G.server.sendMsgByUid(player.uid, 'msg_s2c/PlayerChange', {ghName: change.name});
                G.mongodb.collection('user').updateOne({uid: player.uid}, {$set: {ghName: change.name}});
            });
        }
        if (change.setting) {
            Object.assign(this.data.setting, change.setting);
            this.updateDb({$set: {setting: this.data.setting}});
        }
    }

    /**
     * 新成员加入
     */
    async addPlayer(gud: player) {
        const p: {
            uid: string;
            level: gonghuiLevel;
            joinTime: number;
        } = {
            uid: gud.uid,
            level: 4,
            joinTime: G.time
        };
        this.data.players.push(p);
        this.updateDb({$push: {players: p}});
        PlayerFun.changeAttr(gud.uid, {ghId: this.data._id, ghLevel: 4, ghName: this.data.name});
        G.server.sendMsgByUid(gud.uid, 'msg_s2c/PlayerChange', {
            ghId: this.data._id,
            ghLevel: 4,
            ghName: this.data.name
        });
    }

    /**
     * 踢出成员
     */
    async delPlayer(uid: string) {
        if (this.data.lsgx) {
            this.data.lsgx[uid] = null;
            delete this.data.lsgx[uid];
        }
        this.data.players.splice(this.data.players.findIndex(p => p.uid == uid), 1);
        if (!(this.data?.exp_his || {})[uid]) {
            this.updateDb({$pull: {players: {uid: uid}}});
        } else {
            let need_exp: number = 0;
            // 扣除玩家最近3天内的经验
            let cost_exp = this.data.exp - G.gc.shili_lv[this.data.lv].exp;  // 可以被扣除的经验
            for (let i = 0; i < this.data.exp_his[uid].length; i++) {
                need_exp += this.data.exp_his[uid][i].exp;
            }
            if (need_exp <= cost_exp) {
                this.data.exp -= need_exp
            } else {
                this.data.exp -= cost_exp
            }

            delete this.data.exp_his[uid]

            this.updateDb({
                $set: {exp: this.data.exp},
                $pull: {players: {uid: uid}},
                $unset: {[`exp_his.${uid}`]: 1}
            });
        }

        if (this.data.players.length == 1 && this.data.tanhe) {
            this.data.tanhe = null;
            delete this.data.tanhe;
            this.updateDb({$unset: {tanhe: 1}});
        }
        GHManage.removeRole(uid);
    }

    /**
     * 管理人员
     */
    async managePlayer(uid: string, level: gonghuiLevel) {
        PlayerFun.changeAttr(uid, {ghLevel: level});
        G.server.sendMsgByUid(uid, 'msg_s2c/PlayerChange', {ghLevel: level});
        this.data.players.find(p => p.uid == uid).level = level;
        this.updateDb({$set: {'players.$[elem].level': level}}, {arrayFilters: [{'elem.uid': uid}]});

        if (level == 1) {
            //let p = await G.mongodb.collection('user').findOne({uid: uid});
            let p = await getGud(uid);
            this.data.createPlayer = {
                uid: uid,
                name: p.name
            };
            this.updateDb({$set: {createPlayer: this.data.createPlayer}});
        }
    }

    /**
     * 公会申请列表
     */
    async addApply(gud: player) {
        if (this.data.applyList?.find(v => v.uid == gud.uid)) return;
        if (!this.data.applyList) this.data.applyList = [];
        this.data.applyList.push({uid: gud.uid, time: G.time});
        this.updateDb({$set: {applyList: this.data.applyList}});
    }

    /**
     * 公会申请审批
     */
    async apply(...p: string[]) {
        let players = await G.mongodb.find('user',{uid:{$in:p}});

        for (let i=0;i<players.length;i++) {
            let player = players[i] as any;
            if (this.data.players.length >= this.maxPlayerNum) break;
            if (player.ghId) continue;
            this.addPlayer(player);
        }

        this.data.applyList = this.data.applyList.filter(a => p.includes(a.uid) == false);
        this.updateDb({$set: {applyList: this.data.applyList}});
    }

    /**
     * 获取公会成员列表
     */
    async getAllPlayers() {
        let uids = this.data.players.map(p => p.uid);
        let players = await G.mongodb.collection('user').find({uid:{$in: uids}}).toArray();

        return players.map((p, i) => {
            return {
                player: p,
                lsgx: this.data.lsgx?.[p.uid] || 0
            };
        });
    }

    /**
     * 公会捐献
     */
    async juanxian(index: number, uid: string) {
        let conf = G.gc.shili_com.juanxian[index];

        if (!this.data.lsgx) this.data.lsgx = {};
        if (!this.data.lsgx[uid]) this.data.lsgx[uid] = 0;
        this.data.lsgx[uid] += conf.addExp;

        this.addExp(conf.addExp, uid);

        this.updateDb({
            $set: {lv: this.data.lv},
            $inc: {exp: conf.addExp, ...G.mongodb.createTreeObj({key: 'lsgx', k: uid, val: conf.addExp})}
        });
    }

    async addExp(exp: number, uid: string) {
        this.data.exp += exp;
        let zt = PublicShared.getToDayZeroTime();
        if (!this.data.exp_his) this.data.exp_his = {};
        if (!this.data.exp_his[uid]) this.data.exp_his[uid] = [
            {time: zt, exp: exp}
        ];
        let _set = {};
        // 记录超过3天 并且最后一天记录是昨天
        if (this.data.exp_his[uid][this.data.exp_his[uid].length - 1].time < zt) {
            if (this.data.exp_his[uid].length >= 3) {
                // 移除最早一天的记录
                this.data.exp_his[uid] = this.data.exp_his[uid].slice(1);
            }
            // 添加今天的经验记录
            this.data.exp_his[uid].push({time: zt, exp: exp})
        } else {
            // 今天的经验记录增加
            this.data.exp_his[uid][this.data.exp_his[uid].length - 1].exp += exp
        }

        if (G.gc.shili_lv[this.data.lv + 1] && this.data.exp >= G.gc.shili_lv[this.data.lv + 1].exp) this.data.lv++;

        _set["lv"] = this.data.lv;
        _set[`exp_his.${uid}`] = this.data.exp_his[uid];
        this.updateDb({$inc: {exp: exp}, $set: _set});
    }

    /**
     * 公会弹劾
     */
    async tanhe(uid: string) {
        this.data.tanhe = {
            uid: uid,
            time: G.time + G.gc.shili_com.tanheTime
        };
        this.updateDb({
            $set: {
                tanhe: {
                    uid: uid,
                    time: G.time + G.gc.shili_com.tanheTime
                }
            }
        });
    }

    /**
     * 发送副本奖励邮件
     */
    async sendeMail(fbId: string, players: Array<[string, number]>) {
        let prizeArr = G.gc.shili_fbyj[fbId];

        prizeArr.sort((a, b) => a.rank[0] - b.rank[0]);

        players.sort((a, b) => b[1] - a[1]);

        prizeArr.forEach((conf) => {

            let ps = players.slice(conf.rank[0] - 1, conf.rank[1]);
            ps.forEach((uid, index) => {

                EmailFun.addEmail({
                    uid: uid[0],
                    type: 'system',
                    title: G.gc.shili_com.email.titel,
                    content: G.gc.shili_com.email.content,
                    prize: conf.prize,
                    contentInsertArr: [conf.rank[0] + index]
                });
            });
        });
    }
}