import {ObjectId} from 'mongodb';
import {ApiCall} from 'tsrpc';
import {CollectionShiwu} from '../module/collection_shiwu';
import {PublicShared} from '../shared/public/public';
import {HeroFun} from './hero';
import {call} from './player';

type shiwuType = CollectionShiwu;
type shiwuChange = Partial<Omit<{
    [k in keyof CollectionShiwu]: CollectionShiwu[k]
}, '_id'>>;

export class ShiwuFun {
    static get _conf() {
        return G.gc.shiwucom.base;
    }

    /**获取饰物 */
    static async getShiwu(call: ApiCall, oid: string): Promise<CollectionShiwu>;
    static async getShiwu(call: ApiCall, oid: string[]): Promise<CollectionShiwu[]>;
    static async getShiwu(call: ApiCall, oid: string | string[]) {
        if (typeof oid == 'string') {
            let {_id, ...data} = await G.mongodb.collection('shiwu').findOne(
                {_id: G.mongodb.conversionId(oid)}
            )
            data['_id'] = oid;
            return data
        } else {
            let oids = [].concat(oid).map(v => G.mongodb.conversionId(v))
            let ss = await G.mongodb.collection('shiwu').find({uid: call.uid, _id: {$in: oids}}).toArray();
            return ss.map(v => G.mongodb.conversionIdObj(v));
        }

    }

    /**修改饰物属性 */
    static async changeShiwuAttr(call: call, shiwu: Pick<shiwuType, '_id'> & Partial<Omit<shiwuType, '_id'>>, change: shiwuChange, changeHero = true) {

        //穿戴饰物时该装备穿戴在另一个英雄身上
        if (change.wearId != undefined && shiwu.wearId && shiwu.wearId != change.wearId && changeHero) {
            let takeHero = await HeroFun.getHero(call, shiwu.wearId);
            if (takeHero) {
                let _shiwu = Object.assign({}, takeHero.shiwu);
                let _pos = Object.keys(_shiwu).filter(pos => _shiwu[pos]._id == shiwu._id)[0];

                if (_pos) {
                    _shiwu[_pos] = null;
                    delete _shiwu[_pos];
                    await HeroFun.changeHeroAttr(call, takeHero, {shiwu: _shiwu});
                }
            }
        }

        Object.assign(shiwu, change);

        //属性发生变化并且穿戴在英雄身上时
        if (change.wearId == undefined && shiwu.wearId) {
            let takeHero = await HeroFun.getHero(call, shiwu.wearId);
            if (takeHero) {
                let _shiwu = Object.assign({}, takeHero.shiwu);
                let _pos = Object.keys(_shiwu).filter(pos => _shiwu[pos]._id == shiwu._id)[0];

                if (_pos) {
                    _shiwu[_pos] = this.fmtHeroShiwu(shiwu as shiwuType);
                    await HeroFun.changeHeroAttr(call, takeHero, {shiwu: _shiwu});
                }
            }
        }
        G.mongodb.collection('shiwu').updateOne(
            {uid: call.uid, _id: new ObjectId(shiwu._id)}, {$set: {...change}}
        );
        call.addEventMsg('msg_s2c/ShiwuChange', shiwu._id, change);
    }

    /**随机饰物基础属性 */
    static randomJichu(shiwu: Pick<shiwuType, 'shiwuId' | 'colour'>): shiwuType['jichu'] {
        let conf = G.gc.shiwu[shiwu.shiwuId];
        let jichu: shiwuType['jichu'] = [];
        let buffKeys = Object.keys(conf.buff);

        for (let key of buffKeys) {
            jichu.push(key);
            jichu.push(Math.floor(PublicShared.randomNum(conf.buff[key][0], conf.buff[key][1]) * this._conf.jichu_colour[shiwu.colour]));
        }

        return jichu;
    }

    /**随机饰物附加属性 */
    static randomFujiaAll(shiwu: Pick<shiwuType, 'colour' | 'fujia'> & { shiwuId?: string; }, lockArr: number[] = []) {
        let lv = G.gc.shiwu[shiwu?.shiwuId].lv || 1;
        let index = G.gc.shiwucom.base.fujia_colour.buffRandom.findIndex(v => lv >= v.range[0] && lv <= v.range[1]);
        // 附加属性颜色超过 5 大于等 饰物颜色减1 （随机最大属性池，取其最大buff）
        // let allOrange = shiwu.fujia.filter(f => f?.colour >= 5).length >= shiwu.colour - 1;
        let allOrange = shiwu.fujia.filter(f => f?.colour >= 5).length >= shiwu.fujia.length;

        for (let num = 0; num < shiwu.colour - 1; num++) {
            let fjsx = shiwu.fujia[num];

            // if (!fjsx) {
            //     // 按等级筛选 随机属性池
            //     shiwu.fujia[num] = {
            //         ...this.randomFujia(index)
            //     };
            // } else {
            //     // 无特殊条件 附加颜色超过或等于5  ||  有特殊条件 但被锁定     // 此两种情况不随机
            //     if (!allOrange && fjsx.colour >= 5) continue;
            //     if (allOrange && lockArr.includes(num)) continue;

            //     shiwu.fujia[num] = {
            //         ...this.randomFujia(allOrange ? G.gc.shiwucom.base.fujia_colour.buffRandom.length - 1 : index, allOrange)
            //     };
            // }

            // 普通洗练
            if (!allOrange || !fjsx) {
                if (fjsx && fjsx.colour >= 5) continue
                // 按等级筛选 随机属性池
                shiwu.fujia[num] = {
                    ...this.randomFujia(index)
                };
            } else {
                // 无特殊条件 附加颜色超过或等于5  ||  有特殊条件 但被锁定     // 此两种情况不随机
                if (!allOrange && fjsx.colour >= 5) continue;
                if (allOrange && lockArr.includes(num)) continue;

                shiwu.fujia[num] = {
                    ...this.randomFujia(index, allOrange)
                };
            }
        }
    }

    /**随机饰物专属属性 */
    static randomZhuanshu(shiwu: Pick<shiwuType, 'shiwuId' | 'colour' | 'zhuanshu'>) {
        if (shiwu.colour < 5) return;
        if (!shiwu.zhuanshu && (PublicShared.randomNum(1, 1000) < G.gc.shiwu[shiwu.shiwuId].zhuanshu)) return;

        let isSkill = PublicShared.randomNum(1, 10) <= this._conf.chongzhurate.skill_zhuanshu;
        if (!isSkill) {
            var {p, ...buff} = this._conf.buff_zhuanshu.random();
            var buffKey = Object.keys(buff)[0];
            var buffVal = buff[buffKey];
        }

        shiwu.zhuanshu = {
            hero: this._conf.hero_zhuanshu.random().toString(),
            buff: isSkill ? null : [buffKey, buffVal],
            skill: isSkill ? this._conf.skill_zhuanshu.random().id : '',
        };
    }

    /**格式化为英雄穿戴的饰物数据 */
    static fmtHeroShiwu(shiwu: shiwuType) {
        let {uid, wearId, ...ops} = shiwu;
        return ops;
    }

    static randomFujia(index: number, max = false) {
        let buff = (this._conf.fujia_colour.buffRandom[index].buff as k_v<[number, number]>[]).random();
        let buffKey = Object.keys(buff)[0];
        let buffVal = buff[buffKey];
        let multiplyNum = buffVal[0].toString().split('.').length > 1 ? 10000 : 1;
        // 是否取随机buff最大值
        let val = max ? buffVal[1] : PublicShared.randomNum(buffVal[0] * multiplyNum, buffVal[1] * multiplyNum) / multiplyNum;
        val = val > buffVal[1] ? buffVal[1] : val
        let colour: number;
        let mul = (val - buffVal[0]) / (buffVal[1] - buffVal[0]);

        for (let c of this._conf.fujia_colour.color) {
            if (mul < c.range[0]) break;
            colour = c.color;
            if (mul < c.range[1]) break;
        }

        return {
            colour: colour || this._conf.fujia_colour.color[0].color,
            buffKey: buffKey,
            buffVal: val
        };
    }
}