import {OptionalId, UpdateFilter} from 'mongodb';
import {userInfo} from 'os';
import {ApiCall} from 'tsrpc';
import {CollectionPlayerInfo} from '../module/collection_palyerInfo';
import {
    KuangDongCiShuInfo,
    KuangDongKaiCaiList,
    KuangDongKaiCaiListTmp,
    KuangDongKaiCailog,
    KuangDongKuang
} from '../shared/protocols/kuangdong/PtlOpen';
import {prizeType} from '../shared/protocols/type';
import {PublicShared} from '../shared/public/public';
import {PayFun} from './pay';
import {PlayerFun} from './player';
import { getGud } from './gud';


export class KuangDongfun {
    /**矿洞配置 */
    static async getCon(hdid: string | number) {
        let _con = G.gc.land[hdid.toString()]
        return _con
    }

    /**次数相关初始数据 */
    static async initData() {
        let _res: KuangDongCiShuInfo = {
            eara: {},
            buynum: {},
            time: G.time
        }
        return _res
    }

    /**获取基础数据次数 */
    static async getNumInfo(call: ApiCall) {
        let result = await G.mongodb.collection('playerInfo', 'kuangdong').findOne({uid: call.uid, type: 'kuangdong'});
        let _res: KuangDongCiShuInfo
        if (result && PublicShared.chkSameDate(result.time, G.time)) {
            _res = {
                eara: result?.eara || {},
                buynum: result?.buynum || {},
                time: result.time
            }
        } else {
            _res = await this.initData()
        }
        return _res
    }

    /**占领矿 */
    static async miningZhanLing(call: ApiCall, hdid: number) {
        let _con = await this.getCon(hdid)
        let _tmp: KuangDongKuang
        let _et = G.time + 8 * 3600
        _tmp = {
            ctime: G.time,
            etime: _et,
            uid: call.uid,
            yanshi: 0,
            hdid: hdid,
            kdtype: _con["type"],
            ttl: new Date()
        }
        await this.setminingZhanLing(call.uid, hdid, {$set: _tmp})
        return _tmp
    }

    /**修改矿洞数据 */
    static async setminingZhanLing(uid: string, hdid: number, update) {
        G.mongodb.collection('kuangdong').updateOne(
            {
                uid: uid,
                hdid: hdid
            },
            {
                ...update
            },
            {
                upsert: true
            }
        );
    }

    /**获取所有矿洞信息 */
    static async getKaiCaiList(uid: string) {
        let _r = {}
        let _res: {
            [hdid: string]: KuangDongKaiCaiList;
        } = {}
        let private_hdid = []
        // 排除 非公共街道的数据
        for (let grid in G.gc.land) {
            if (G.gc.land[grid].public_map != 1) {
                private_hdid.push(Number(grid))
            }
        }
        //这里总共极限是63条数据
        let _kdList = await G.mongodb.collection('kuangdong').find({
            $or: [{hdid: {$nin: private_hdid}}, {uid: uid}]
        }).toArray();

        //从kdlist中筛选出uid字段
        let uids = _kdList.map(item => item.uid);

        let userInfos;
        if (uids.length > 0) {
            //一次性拉取所有玩家
            userInfos = await this.getUserInfo(uids)
        }

        let _prize = {}
        for (let index = 0; index < _kdList.length; index++) {
            const element = _kdList[index];
            let _hdid = element.hdid
            // 时间到直接结算奖励
            if (element.etime + element.yanshi <= G.time) {
                let _p = await this.getKuangDongPrize(_hdid, element)
                if (!_prize[element.uid]) _prize[element.uid] = []
                _prize[element.uid] = _prize[element.uid].concat(_p)
                continue
            }
            element._id = element._id.toString()
            //let _tmp = await this.getUserInfo(element.uid)
            element.userinfo = (userInfos?.[element.uid] || {}) as any;
            _res[_hdid.toString()] = element
        }
        _r["kdinfo"] = _res
        _r["prize"] = _prize
        return _r
    }

    /**获取个人信息 */
    static async getUserInfo(uid: string | string[]) {
        let _tmp: KuangDongKaiCaiListTmp
        let uids = [];

        if (typeof (uid) == 'string') {
            //兼容原来的逻辑，保持对string的支持
            uids = [uid]
        } else {
            uids = uid;
        }
        let info = {};
        let _guds = await G.mongodb.find('user', {uid: {$in: uids}}, ['uid', 'name', 'lv', 'power', 'ghId', 'ghName', 'head', 'headFrame']);
        _guds.forEach(v => {
            info[v.uid] = {
                name: v.name,
                lv: v.lv,
                power: v.power,
                ghId: v.ghId,
                ghName: v.ghName,
                head: v.head,
                headFrame: v.headFrame
            }
        });

        if (typeof (uid) == 'string') {
            //兼容原来的逻辑，保持对string的支持
            return info[uid] as any;
        } else {
            return info;
        }
    }

    /**获取矿洞的详细信息 */
    static async getKaiCaiInfo(hdid: number, uid: string = '') {
        let _where = {hdid: hdid}
        if (uid) _where["uid"] = uid
        let _kdInfo = await G.mongodb.collection('kuangdong').findOne(_where)
        return _kdInfo
    }

    /**获取矿洞奖励 */
    static async getKuangDongPrize(hdid: number, kdInfo?: KuangDongKuang, data?: {}) {
        if (!kdInfo) {
            kdInfo = await this.getKaiCaiInfo(hdid)
        }
        if (!kdInfo) return []
        let _con = await this.getCon(hdid)
        let _kcTime = G.time + kdInfo.yanshi - kdInfo.ctime
        //let _gud = await G.mongodb.collection('user').findOne({uid: kdInfo.uid})
        let _gud = await getGud(kdInfo.uid)
        let gamer_lv = _gud.lv
        // @ts-ignore
        let prize: prizeType[] = _con.reward
        // let prize: prizeType[] = [{ a: 'attr', t: 'rmbmoney', n: 50 }]           // todo 待接入配置
        if (_kcTime > 8 * 3600) _kcTime = 8 * 3600 + kdInfo.yanshi   // 设置最大时长
        prize[0]["n"] = Math.floor(eval(_con.formula) * _kcTime)

        if (_con.public_map == 1){
            await G.mongodb.collection('kuangdong').deleteOne({hdid: hdid})
        }else {
            await G.mongodb.collection('kuangdong').deleteOne({hdid: hdid, uid: kdInfo.uid})
        }
        if (prize[0]["n"] > 0) {
            // 发奖删数据加日志
            PlayerFun.sendPrize(PayFun.getCall(_gud), prize)
        } else {
            prize = []
        }

        // 矿洞日志
        let _log: KuangDongKaiCailog = {
            uid: kdInfo.uid,
            hdid: hdid,
            name: _gud.name,
            ctime: G.time,
            msgtype: 1,
            prize: prize,
            longtime: _kcTime
        }
        Object.assign(_log, data)
        await this.newKuangDongLog(_log)
        return prize
    }

    /**添加矿洞日志 */
    static async newKuangDongLog(sendData: KuangDongKaiCailog) {
        sendData.longtime = (sendData.longtime < 8 * 3600) ? sendData.longtime : 8 * 3600
        const msgListLen = 20
        // let conns = G.server.connections;
        G.mongodb.collection('ghbzcjlog').updateOne(
            {type: "kuangdong_msg"},
            {$push: {list: {$each: [sendData], $slice: -msgListLen}}},
            {upsert: true}
        );
        // G.server.broadcastMsg('msg_s2c/GongHuiBaoZang', [sendData], conns);
    }

    /**红点 */
    static async getHongDian(call: ApiCall) {
        let _res = {
            show: false
        }
        // 次数信息
        let _mydata = await this.getNumInfo(call)
        // 配置可挑战次数
        let _fightNumCon = G.gc.com.TerritoryFight_ChallengesNum.value

        // 2023.8.29 策划新加 所有矿所有区域，总次数限制（目前各区域一次，总3次）
        let _allAreaDayNum = G.gc.com.dpzd_quyu_num.value
        let _mykdList = await G.mongodb.collection('kuangdong').find({uid: call.uid}).toArray()
        let _tqNum = Object.keys(call.conn.gud.shoucangping).indexOf("4") != -1 ? 1 : 0
        if (_mykdList.length >= _allAreaDayNum + _tqNum) {
            return _res;
        }

        const _area = [1, 2, 3]
        for (let index = 0; index < _area.length; index++) {
            const element = _area[index];
            // 购买次数
            let _buyNum = _mydata.buynum?.[element] || 0
            // 已挑战次数
            let _fightNum = _mydata.eara?.[element] || 0
            // 挑战次数不足
            if (_fightNumCon + _buyNum > _fightNum) {
                _res.show = true
                break
            }
        }
        return _res
    }
}