import {random} from "mathjs";
import {player} from "../protocols/user/type";
import {Player} from "./Player";
import {RunAfterSkill} from "./afterSkill";
import {BuffBase} from "./fightBuff/buffBase";
import * as BuffClass from './fightBuff/buffExtends';
import {FightControl} from "./fightCntrol";
import {getSkillConf, randNumber, randomSkill} from "./fightFun";
import {
    EmitDataType,
    FightObj,
    afterSkillType,
    atkRoleInfo_Type,
    buffDataType,
    dpsinfoType,
    joinFightData,
    modifyHpType,
    roleDataType
} from "./fightType";
import {runPassiveSkillBase} from "./passiveSkill/runPassiveSkill";
import {SkillBase} from "./skill/skillBase";
import { PublicShared } from "../public/public";
import { PassiveSkillBase } from "./passiveSkill/passiveSkillBase";

export class Role {
    rid: string;
    curAtkSkill: SkillBase;
    /**记录技能的选中目标 */
    skillTargets: k_v<Role[]> = {};
    lastSkillTargets: Role[] = [];
    lastSkillId: string;
    _lastHitMe: FightObj = null;
    buffs: k_v<any> = {};
    passiveSkills: k_v<any> = {};
    /**主动复活英雄数量*/
    activeResurrect = 0;
    skillLv = 1;
    hudunzhi = 0;
    addpkNum = 0;

    release(){
        for(let buffid in this.buffs){
            this.buffs[buffid].release();
        }
        for(let passiveid in this.passiveSkills){
            this.passiveSkills[passiveid].release();
        }
        this.curAtkSkill?.release();
        this.curAtkSkill = null;
        this.skillTargets = null;
        this.lastSkillTargets = null;
        this.lastSkillId = null;
        this._lastHitMe = null;
        this.buffs = null;
        this.passiveSkills = null;
    }

    get skillId() {
        let heroId = this.roleData.heroId;
        let jieji = this.roleData.jieji || 0;
        let heroskill = G.gc.heroskill[heroId][jieji].skill;
        return randomSkill(heroskill);
    }

    get isDead() {
        return this.roleData.dead || false;
    }

    get lockHp() {
        return this.roleData.lockHp || false;
    }

    get isCanAtk() {
        return this.hasbuff('xuanyun') || this.hasbuff('kongju') || this.hasbuff('shuimian');
    }

    get rolePlayer() {
        const side = this.roleData.side;
        return this.fightControl['player_' + side];
    }

    get lastHitMe() {
        return this._lastHitMe;
    }

    set lastHitMe(role: FightObj) {
        if (role.rid.indexOf('player') != -1) return;
        this._lastHitMe = role;
    }

    get isHasFightSkills() {
        return true;
    }

    getLastTargetsBySkillID(skillid: string) {
        /**获取最后一次触发skillid技能时，该技能的选敌目标*/
        return this.skillTargets[skillid] || [];
    }

    constructor(public fightControl: FightControl, public roleData: roleDataType) {
        this.rid = 'role_' + roleData.side + '_' + roleData.pos;
    }

    runSkillClass() {
        let _skillId = this.skillId;
        let skillconf = getSkillConf(_skillId);
        if (!skillconf) console.error('没有技能-->' + _skillId);
        this.debug(() => {
            console.log(`#runSkillClass~~~rid-->${this.rid} skillid-->${_skillId}`);
        });

        return new SkillBase(this, skillconf);
    }

    atk() {
        if (this.isCanAtk) return;
        this.fightControl.event.emit('fightEvent_startatk', {
            toRole: this
        });
        // fromRole行动的角色
        // skillConf 使用的技能
        // toRole 目标
        //上一个指针release
        this.curAtkSkill?.release();
        this.curAtkSkill = this.runSkillClass();
        this.bloodReturn();
        this.debug(() => {
            console.log(`this.rid is atking`);
        });
    }

    /**
     * 攻击完，回血量的计算
     * @param dpsinfo
     */
    bloodReturn(dpsinfo?: { targets: string[], rolesInfo: k_v<atkRoleInfo_Type>; }) {
        if (this.hasbuff("noaddhp")) return;

        let changehp = 0;
        let curHp = this.getData('hp');
        let curMaxHp = this.getData('maxHp');

        if (dpsinfo != undefined) {
            let xixuepro = this.getDataPro('xixue') - this.getData('addhpdrop');
            let dps = 0;
            for (let key in dpsinfo.rolesInfo) {
                dps += (dpsinfo.rolesInfo[key].ov - dpsinfo.rolesInfo[key].nv);
            }
            changehp = Math.abs(dps) * xixuepro;
        } else {
            let addhp = this.getData('addhp') - this.getData('addhpdrop');
            let addmaxhp = this.getData('addmaxhp') - this.getData('addhpdrop');
            changehp = curHp * addhp + curMaxHp * addmaxhp;
        }
        if (changehp == 0) return;
        let nv = curHp + changehp;
        nv = nv > curMaxHp ? curMaxHp : nv;
        this.setData('hp', nv);
        this.fightControl.record({
            act: 'addHp',
            fromRole: this.rid,
            why: 'buff',
            buffId: "",
            ov: curHp,
            nv: nv
        });
    }

    setData(key: string, val: number) {
        this.roleData.attr[key] = val;
    }

    getData(key: string, defaultValue: number = 0) {
        if (key == 'lv' && (this.roleData.attr['trueLv'] || this.roleData['trueLv'])) key = 'trueLv'
        let keydata = this.roleData.attr[key];
        if (!keydata) return this.roleData[key] || defaultValue;
        return keydata;
    }

    getDataPro(key: string) {
        return this.getData(key + 'pro') - this.getData(key + 'drop');
    }

    modifyHp(dpsinfo: dpsinfoType, extData: modifyHpType) {
        let will = this.isWillDead(dpsinfo, extData);
        if (will) {
            this.fightControl.event.emit('fight_willDead', {toRole: this});
        }
        this._modifyHp(dpsinfo, extData);
    }

    _modifyHp(dpsinfo: dpsinfoType, extData: modifyHpType) {
        if (this.isDead) return;

        if (/* dpsinfo.num == 0 ||  */this.lockHp) return;

        if (dpsinfo.num < 0) {
            //记录总伤害
            const _side = this.roleData.side == "0" ? "1" : "0";
            this.fightControl.totalDamage[_side] += Math.abs(dpsinfo.num);

            //统计每个英雄的战斗数据
            this.fightControl.recordStatistics(dpsinfo.fromRole, 'hit', Math.abs(dpsinfo.num));
            this.fightControl.recordStatistics(dpsinfo.toRole, "def", Math.abs(dpsinfo.num));
        } else if (dpsinfo.num > 0) {
        }

        let dpsNum = dpsinfo.num;

        if (this.hudunzhi > 0 && dpsNum < 0) {
            dpsNum += this.hudunzhi;
            if (dpsNum > 0) dpsNum = 0;
            this.hudunzhi += dpsinfo.num;
            if (this.hudunzhi < 0) this.hudunzhi = 0;
        }

        let hp = this.getData('hp') + dpsNum;
        if (hp < 0) hp = 0;
        if (hp > this.getData('maxHp')) hp = this.getData('maxHp');
        this.setData('hp', hp);
        if (hp == 0) this.Dead(dpsinfo, extData);

        //afterSkill_atkdamage和afterSkill_bisha的skillType是afterAtk
        //只有这2种原因引起的掉血，才会广播byatk和doatk
        if (dpsinfo.num <= 0 && dpsinfo.fromRole.rid != dpsinfo.toRole.rid && extData.skillType == 'afterAtk') {
            this.fightControl.event.emit('fightEvent_byatk', {
                fromRole: dpsinfo.fromRole,   //攻击者
                toRole: this, //被击者
                skillId: extData.skillId,
                skillType: extData.skillType,
                dps: dpsinfo.num
            });

            this.fightControl.event.emit('fightEvent_doatk', {
                fromRole: this,  //受击
                toRole: dpsinfo.fromRole, //攻击
                skillId: extData.skillId,
                skillType: extData.skillType,
                dps: dpsinfo.num
            });
        }
    }

    isWillDead(dpsinfo: dpsinfoType, extData: modifyHpType) {
        if (this.lockHp || dpsinfo.dps > 0) return false;

        /** 后续这里还要添加护盾的血量值计算 */

        let hp = this.getData('hp') + dpsinfo.dps;
        return hp <= 0;
    }

    Dead(dpsinfo: dpsinfoType, extData: modifyHpType) {
        this.roleData.dead = true;
        this.clearAllBuff('roleDead');
        this.clearAllPassiveSkill('roleDead');
        this.fightControl.record({act: 'roleDead', isFuhou: false, fromRole: this.rid});
        this.fightControl.event.emit('fightEvent_dead', {
            toRole: this,
            fromRole: dpsinfo.fromRole
        });
        // this.fightControl.checkFightEnd()
    }

    /**
     *
     * @param skillinfo ：「施放者 作用目标 施放的主技能 当前技能 作用目标数」
     */
    runAfterSkill(skillinfo: afterSkillType, where?: string) {
        let skillconf = skillinfo.skillConf;
        let runSkillInfo = null;
        switch (skillconf.type) {
            case 1:
                // 主动技能
                console.error('主动技能不可通过runskill来调用');
                break;
            case 2:
                // 被动技能
                var passiveid = skillinfo.skillConf.skillid;
                skillinfo.toRole.clearAllPassiveSkill('clear', function (skill) {
                    return skill.skillConf.skillid == passiveid;
                });
                runPassiveSkillBase(skillinfo);
                break;
            case 3:
                // 攻击后技能
                runSkillInfo = RunAfterSkill.run(skillinfo, where);
                break;
        }

        return runSkillInfo;
    }

    addBuff(buffdata: buffDataType) {
        // if (!checkBuffEmit(this, buffdata.toRole, buffdata.skillConf.checkData)) return;
        let randnum = buffdata.skillConf.randnum;
        if (typeof randnum == 'string') {
            randnum = PublicShared.eval(randnum, {slv: this.skillLv});
        }
        if (randNumber() > randnum) return;
        let group = buffdata.skillConf.group;
        /**同一buff组, 只能存在一个buff
         buff组是否有相同的，如果有，则判断已存在的buff的buffid，如果不一样，则先清掉原来的，再叠加新的*/
        let sameGroupBuff = this.getBuffByGroup(group);
        if (sameGroupBuff && sameGroupBuff.data.buffid != buffdata.buffid) {
            sameGroupBuff.clear('sameGroup');
        }

        let oldBuff = this.buffs[buffdata.buffid];
        // 叠加层数=0，表示不能叠加，则先清掉原来的，再叠加新的

        let buffType = buffdata.skillConf.sxleixing;
        if (buffType == 'attr') {
            buffType = Object.keys(buffdata.skillConf.xiaoguocanshu);
        } else {
            buffType = [buffType];
        }

        // if (!oldBuff || buffdata.skillConf.diejiacengshu == "0") {
        if (!oldBuff || oldBuff.remainingRounds < 0) {
            // oldbuff在剩余0回合的时候，重新施加，不需要清除，会造成重复清除
            // oldBuff && oldBuff.clear('oldbuff');
            //直接新加buff
            this.debug(function () {
                console.log(`### buff 触发buff buffid:${buffdata.buffid} 生效类型:${buffdata.skillConf.skillConf.sxleixing}`);
            });
            let sxleixing = buffdata.skillConf.sxleixing;

            if (BuffClass['Buff_' + sxleixing]) {
                this.buffs[buffdata.buffid] = new BuffClass['Buff_' + sxleixing](buffdata);
            } else {
                // 比如修改数值类的buff, 基类统一处理
                this.buffs[buffdata.buffid] = new BuffBase(buffdata);
            }

            buffType.forEach(_type => {
                this.fightControl.record({
                    act: 'addBuff',
                    fromRole: buffdata.fromRole.rid,
                    toRole: buffdata.toRole.rid,
                    skillId: buffdata.buffid,
                    buffType: _type,
                    buffId: this.buffs[buffdata.buffid]._BuffId
                });
            })

            this.buffs[buffdata.buffid] && this.buffs[buffdata.buffid].start();
            return;
        }


        // 叠加效果：retime = 重置回合 overlaponly = 不重置回合，仅叠加效果
        if (oldBuff) {
            this.debug(function () {
                console.log('### buff 叠加效果:', oldBuff.data.diejiaxiaoguo);
            });

            /** 这里重置buff是不需要发送添加buff的，只需要重置剩余回合 */
            // buffType.forEach(_type => {
            //     this.fightControl.record({
            //         act: 'addBuff',
            //         fromRole: buffdata.fromRole.rid,
            //         toRole: buffdata.toRole.rid,
            //         skillId: buffdata.buffid,
            //         buffType: _type,
            //         buffId: oldBuff._BuffId
            //     });
            // })

            // todo 目前没有需要叠加的buff，如需要添加，这部分逻辑可能要修改
            if (oldBuff.data.skillConf.jiejiaxiaoguo == 'retime') {
                // 重置持续回合
                oldBuff.retime(); //  buffdata,{'newBuff':true}
            } else if (oldBuff.data.skillConf.jiejiaxiaoguo == 'overlaponly') {
                // 叠加效果, 且持续回合不变
                oldBuff.overlaponly(buffdata, {'newBuff': true});
            } else if (oldBuff.data.skillConf.jiejiaxiaoguo == 'overlap') {
                // 叠加效果, 且重置回合
                if (oldBuff.overlaponly(buffdata, {'newBuff': true})) {
                    oldBuff.retime(); //  buffdata
                }
            } else {
                console.error('未知jiejiaxiaoguo=', oldBuff.data.skillConf.jiejiaxiaoguo);
            }
        }
    }

    getBuffByType(sxleixing: string | string[]) {
        let rebuffs = [];
        sxleixing = [].concat(sxleixing);
        for (let key in this.buffs) {
            if (sxleixing.indexOf(this.buffs[key].data.skillConf.sxleixing) > -1) {
                rebuffs.push(this.buffs[key]);
            }
        }
        return rebuffs;
    }

    /**同一buff组，只能存在一个buff */
    getBuffByGroup(buffgroup: string) {
        for (var buffid in this.buffs) {
            if (this.buffs[buffid].data.skillConf.group == buffgroup) {
                return this.buffs[buffid];
            }
        }
        return null;
    }

    hasbuff(buffid: string): boolean {
        return this.getBuffByType(buffid).length > 0;
    }

    clearAllBuff(why: string, filter?: (skill: k_v<any>) => boolean) {
        for (let buffid in this.buffs) {
            if (!filter || filter(this.buffs[buffid])) {
                this.buffs[buffid].clear('clearAll_' + why);
            }
        }
    }

    clearBuff(sxleixing: string) {
        let buff = this.getBuffByType(sxleixing);
        buff.forEach(_b => {
            _b.clear();
        })
    }

    clearAllPassiveSkill(why: string, filter?: (skill: k_v<any>) => boolean) {
        for (let skillid in this.passiveSkills) {
            if (!filter || filter(this.passiveSkills[skillid])) {
                this.passiveSkills[skillid].clear('clearAll_' + why);
            }
        }
    }

    debug(callback: () => void) {
        //callback();
    }
}

/**
 *
 * @param fromRole buff 的释放者
 * @param toRole buff 的拥有者
 * @param checkData 检测条件
 * @returns
 */
export function checkBuffEmit(fromRole: Role, toRole: Role, checkData: k_v<any>) {
    let keys = Object.keys(checkData);
    if (keys.length == 0) return true;
    /** 判断buff是否可以触发 */
    return true;
}
