import {ObjectId} from 'mongodb';
import {maxPosNum} from '../api_s2c/hero/ApiChangePos';
import {CollectionHero} from '../module/collection_hero';
import {Wjjl} from '../module/collection_wjjl';
import {prizeType} from '../shared/protocols/type';
import {EquipShared} from '../shared/public/equip';
import {HeroShared} from '../shared/public/hero';
import {PeijianShared} from '../shared/public/peijian';
import {EquipFun} from './equip';
import {PeijianFun} from './peijian';
import {call, PlayerFun} from './player';
import {ShiwuFun} from './shiwu';

type heroChange = Partial<Omit<{
    [k in keyof CollectionHero]: CollectionHero[k]
}, '_id'>>;

export class HeroFun {
    /**修改英雄属性 */
    static async changeHeroAttr(call: call, hero: CollectionHero, change: heroChange) {
        if (Object.keys(change).length < 1) return;

        Object.assign(hero, change);
        hero.zhanli = HeroShared.getHeroZhanLi(hero, call.otherBuff, Object.values(call.conn.gud.heroPos).indexOf(hero._id));
        change.zhanli = hero.zhanli;

        await G.mongodb.collection('hero').updateOne({uid: call.uid, _id: new ObjectId(hero._id)}, {
            $set: {
                ...change
            }
        });

        call.addEventMsg('msg_s2c/HeroChange', hero._id, change);

        if (Object.values(call.conn.heroPos).includes(hero._id)) call.conn.refreshPower();
    }

    /**获取英雄 */
    static async getHero(call: call, oid: string) {
        let {_id, ...info} = await G.mongodb.collection("hero").findOne({
            _id: G.mongodb.conversionId(oid)
        })
        let data = Object.assign({_id: _id.toHexString()}, info)
        return data
    }

    /**获取多个英雄 */
    static async getHeros(call: { uid: string; }, _ids: string[]) {
        let s = await G.mongodb.collection('hero').find({
            uid: call.uid, _id: {
                $in: _ids.map(_id => G.mongodb.conversionId(_id))
            }
        }).toArray();
        return s.map(h => G.mongodb.conversionIdObj(h));
    }

    /**删除英雄 */
    static async delHero(call: call, _hero: CollectionHero): Promise<prizeType[]>;
    static async delHero(call: call, _id: string): Promise<prizeType[]>;
    static async delHero(call: call, v: string | CollectionHero) {
        let hero = typeof v == 'string' ? await this.getHero(call, v) : v;
        let prize: prizeType[] = [];

        if (hero?.lv > 1) {
            for (let lv = 1; lv < hero.lv; lv++) {
                prize.push(...HeroShared.getHeroLvUpNeed(hero.heroId, lv));
            }

            hero.lv = 1;
        }

        if (hero?.jieji) {
            for (let jieji = 0; jieji < hero.jieji; jieji++) {
                let need = HeroShared.getHeroJinJieNeed(hero.heroId, jieji);
                need = need.map(n => {
                    if (n.a == 'hero') {
                        return {
                            a: 'item',
                            t: n.t,
                            n: JSON.parse(JSON.stringify(G.gc.item[n.t].num)) * n.n
                        };
                    } else return n;
                });
                prize.push(...need);
            }

            hero.jieji = 0;
        }

        if (hero?.weapon) {
            for (let jieji = 1; jieji <= hero.weapon.jieji; jieji++) {
                let confs = G.gc.zhuanshu[G.gc.hero[hero.heroId].zhuanshu][jieji];
                prize.push(...Object.values(confs).filter(c => {
                    if (jieji < hero.weapon.jieji) return true;
                    else return c.star <= hero.weapon.star;
                }).map(c => c.need).reduce((a, b) => a.concat(b)));
            }

            hero.weapon = {jieji: 0, star: 0, starProbability: 0};
        }

        if (hero?.qiannneg) {
            for (let [type, lv] of Object.entries(hero.qiannneg)) {
                let needs = Object.values(G.gc.hero_qianneng[type]).filter(c => lv >= c.lv).map(c => c.need);
                needs.length > 0 && prize.push(...needs.reduce((a, b) => a.concat(b)));
            }

            hero.qiannneg = Object.fromEntries(Object.keys(G.gc.hero_qianneng).map(k => [k, 0]));
        }

        if (hero?.awake) {
            let p = Object.values(G.gc.hero_jx).filter(c => c.lv <= hero.awake).map(c => [].concat(c.item_cos, {
                a: 'item',
                t: hero.heroId,
                n: c.HeroDebris_Cos
            })).reduce((a, b) => a.concat(b));
            prize.push(...p);

            hero.awake = 0;
            hero.talent = Object.fromEntries(Object.keys(G.gc.hero_tf).map(t => [t, 0]));
        }

        if (hero?.equip) {
            for (let pos in hero.equip) {
                hero.equip[pos] && await EquipFun.changeEquipAttr(call, EquipShared.fmtEquip(hero.equip[pos]), {wearaId: ''}, false);
            }

            hero.equip = {};
        }

        if (hero?.shiwu) {
            for (let pos in hero.shiwu) {
                hero.shiwu[pos] && await ShiwuFun.changeShiwuAttr(call, hero.shiwu[pos], {wearId: ''}, false);
            }

            hero.shiwu = {};
        }

        if (hero?.peijian) {
            for (let pos in hero.peijian) {
                hero.peijian[pos] && await PeijianFun.changeAttr(call, PeijianShared.fmt(hero.peijian[pos]), {wearId: ''}, false);
            }

            hero.peijian = Object.fromEntries(Object.keys(hero.peijian).map(pos => [pos, '']));
        }

        return prize;
    }

    /**自动上阵 */
    static async setHeroPos(call: call) {
        let _hero = await G.mongodb.collection('hero').findOne({uid: call.conn.gud.uid})
        let heroPos = Object.assign({}, call.conn.heroPos);
        let fightHeros = call.conn.gud.fightHeros.map(id => id);
        let posArr = Object.keys(heroPos).filter(pos => call.conn.gud.lv >= G.gc.herocom.szHeroLimit[pos]);

        let matrixPos = JSON.parse(JSON.stringify(call.conn.gud.matrixPos));
        let setPos = posArr.filter(pos => heroPos[pos] == '')[0];
        let _heroId = _hero._id.toString()
        heroPos[setPos] = _heroId;

        for (let type in matrixPos) {
            if (!matrixPos[type][setPos]) matrixPos[type][setPos] = _heroId;
            else {
                for (let pos = 1; pos <= maxPosNum; pos++) {
                    if (!matrixPos[type][pos]) matrixPos[type][pos] = _heroId;
                }
            }
        }
        fightHeros.push(_hero.heroId.toString());

        Wjjl.setVal(call.conn.gud.uid, 'fight_hero_colour_4', fightHeros.map(id => G.gc.hero[id].colour).filter(c => c >= 4).length);

        await PlayerFun.addAttr(call, {heroPos: heroPos, fightHeros: fightHeros, matrixPos: matrixPos});
        call.conn.refreshPower();

        return
    }

    /**
     * 检查阵型英雄，如不对自动替换
     */
    static checkMatrixPosAndChange(call: call, heroPos, matrixPos) {

        let heroList = R.values(heroPos)

        R.forEachObjIndexed((value, key) => {
            let a = false
            R.forEachObjIndexed((v, k) => {
                if (!R.find(i => i == v)(heroList)) {
                    a = true
                }
            })(value)
            if (a) {
                matrixPos[key] = heroPos
            }
        })(matrixPos)

        return matrixPos
    };


}