
import { getAtkTarget } from "./atkTarget";
import { getSkillConf, randNumber } from "./fightFun";
import { FightObj, fightResult, joinFightData, recordDataType, roleDataType } from "./fightType";
import { Player } from "./Player";
import { Role } from "./Role";

export class FightControl {
    startTime: number = Date.now();
    //所有战斗成员，包含双方的所有“伙伴”
    fightRoles: k_v<Role> = {};
    //所有战斗对象，包含了双方的“伙伴”和“主角”
    fightRolesArr: FightObj[] = [];
    fightOver = false;
    roundNums = 0;
    recordData: recordDataType[] = [];
    event = new G.getEvent(999);
    // event = new myEventEmitter();
    initial: joinFightData[];
    winSide: number;
    totalDamage = { "0": 0, "1": 0 };
    //战斗统计
    fightStatistics: { [k: string]: { [k: string]: number; }; } = {};
    player_0: FightObj = null;
    player_1: FightObj = null;
    recordSkillDps: { [key: string]: number } = {};
    constructor(public DATA: joinFightData[], public maxRoundNums: number = 30, public fightType: 'pvp' | 'pve' = 'pve') {
        this.initial = JSON.parse(JSON.stringify(DATA));
        this.initControl();
        this.addFightObj();
        this.startTurnRound();
    }

    /**
     * 释放内存资源
     */
    release(){
        this.fightRolesArr.map( obj =>{
            obj?.release();
        });
        this.fightRoles = null;
        this.fightRolesArr = null;
        this.recordData = null;
        this.event.removeAllListeners();
        this.event = null;
        this.initial = null;
        this.fightStatistics = null;
        this.player_0 = null;
        this.player_1 = null;
        this.recordSkillDps = null;
        this.DATA = null;
    }

    initControl() {
        // this.event.setMaxListeners(1000);
    }

    addFightObj() {
        for (let side = 0; side < this.DATA.length; side++) {
            this.DATA[side].player.side = side.toString();
            this.DATA[side].player.pos = 7;

            let _data = this.DATA[side];
            let _joindataRole = _data.roles;
            for (let key in _joindataRole) {
                let d = _joindataRole[key];
                d.pos = key;
                d.side = side.toString();
                this.addRole(_joindataRole[key]);
            }
            this.addPlyer(_data.player);
        };
    }

    addRole(data: roleDataType) {
        if (data.attr.hp <= 0) return;
        let role = new Role(this, data);
        this.fightRoles[role.rid] = role;
        this.fightRolesArr.push(role);
    }

    addPlyer(data: joinFightData['player']) {
        let player = new Player(this, data);
        this.fightRolesArr.push(player);
        this['player_' + data.side] = player;
    }


    /**
     * 战斗循环
     */
    startTurnRound() {
        while (!this.fightOver) {
            this._tunrRound();
        }
    }

    /**
     * 每轮次战斗具体实现
     */
    _tunrRound() {
        if (this.roundNums == 0) this.beforeSkill();

        this.roundNums += 1;
        this.record({ act: 'trun', roundNums: this.roundNums });
        this.event.emit('fightEvent_roundNums', { "turn": this.roundNums });


        this.fightRolesArr.sort((a, b) => {
            let aSeep = a.getData('speed') * (1 + a.getDataPro('speed'));
            let bSeep = b.getData('speed') * (1 + b.getDataPro('speed'));
            if (aSeep != bSeep) {
                return bSeep - aSeep;
            } else {
                return parseInt(a.roleData.side) - parseInt(b.roleData.side)
            }
        });
        // if(G.config.debug) console.log(this.roundNums)
        this.fightRolesArr.map(role => role.addpkNum = 0);
        for (var i = 0; i < this.fightRolesArr.length; i++) {
            this.checkEnd();
            if (this.fightOver) break;
            let role = this.fightRolesArr[i];
            if (role.isDead || !role.isHasFightSkills) continue;
            this.record({ act: 'startAct', fromRole: role.rid });
            role.atk();
            this.record({ act: 'stopAct', fromRole: role.rid });
            //判断是否能两次行动
            if (this.atkAgain(role)) {
                i--;
            }
            if (role.hasbuff("addpk") && role.addpkNum == 0) {
                i--;
                role.clearBuff("addpk");
                role.addpkNum += 1
            }
        }

        this.checkEnd();
    }

    atkAgain(role: FightObj) {
        let rid = role.rid;
        if (rid.indexOf('player') != -1) return false;
        let shiqi = role.getData('shiqi') * (1 + role.getDataPro('shiqi'));
        let randnum = 1 + shiqi / (shiqi + 100 + role.getData('lv') * 100);
        return randNumber() > randnum;
    }

    /** 战前技能检查  */
    beforeSkill() {
        this.eachLiveRoles((role) => {
            let heroId = role.roleData.heroId;
            // let shiwu = role.roleData?.shiwu || {};
            // let talent = role.roleData?.talent || {};
            let skills = G.gc.heroskill[heroId][role.roleData.jieji || 0].bdskill || [];
            skills = skills.concat(role.roleData.attr.skillArr);

            // for (let key in shiwu) {
            //     let zhushuan = shiwu[key]?.zhuanshu;
            //     if (!zhushuan) continue;
            //     if (zhushuan.skill) skills.push(zhushuan.skill);
            // };
            // const hero_tf = G.gc.hero_tf;
            // for (let key in talent) {
            //     let cdata = hero_tf[key][talent[key]];
            //     if (cdata && cdata.skill_effect) skills.push(cdata.skill_effect);
            // }

            // skills.push('tx06309');

            // if (!skills) return;
            skills.forEach(_skill => {
                let askillconf = getSkillConf(_skill);
                if (!askillconf) return console.log('没有技能配置-->', _skill);
                let randnum = askillconf.randnum;
                if (randnum == '' || randNumber() > randnum) return;
                let targets = getAtkTarget(role.fightControl, role , askillconf);
                targets.forEach(_target => {
                    _target.runAfterSkill({
                        fromRole: role,
                        toRole: _target,
                        fromSkill: null,
                        skillConf: askillconf,
                        targetCount: targets.length
                    }, 'beforeSkill');
                });
            });
        });
    }

    checkEnd() {
        if (this.fightOver) return;
        if (this.roundNums > this.maxRoundNums) this.fightOver = true;

        let side0Arr = [], side1Arr = [];
        this.eachLiveRoles((role) => {
            if (role.roleData.side == '0') {
                side0Arr.push(role);
            } else {
                side1Arr.push(role);
            }
        });

        if (side0Arr.length == 0 || side1Arr.length == 0) {
            this.fightOver = true;
        }

        if (this.fightOver) this.stopFight(side0Arr, side1Arr);
    }

    stopFight(side0Arr: Role[], side1Arr: Role[]) {
        /* 
        获胜条件判断：
            数量相同，人数多的获胜
            人数一致，战力低的获胜
            战力一直， 随机获胜
        */
        let winside = 0;
        if (this.fightType == "pve") {
            winside = side1Arr.length != 0 ? 1 : 0;
        } else {
            let power0 = this.DATA[0].player.power, power1 = this.DATA[1].player.power;
            if (side0Arr.length > side1Arr.length) {
                winside = 0;
            } else if (side0Arr.length < side1Arr.length) {
                winside = 1;
            } else if (power0 < power1) {
                winside = 0;
            } else if (power0 > power1) {
                winside = 1;
            } else {
                winside = [0, 1].random();
            }
        }

        this.winSide = winside as 1 | 0;
        this.record({ act: 'fightEnd', winSide: this.winSide });
        this.event.removeAllListeners()
    }

    eachLiveRoles(callback: (role: Role) => void) {
        for (let rid in this.fightRoles) {
            // if (this.fightOver) return;
            if (!this.fightRoles[rid]) continue;
            // 排除死亡
            if (this.fightRoles[rid].isDead) continue;
            callback && callback(this.fightRoles[rid]);
        }
    }

    eachDeadRoles(callback: (role: Role) => void) {
        for (let rid in this.fightRoles) {
            if (this.fightOver) return;
            if (!this.fightRoles[rid]) continue;
            if (!this.fightRoles[rid].isDead) continue;
            callback && callback(this.fightRoles[rid]);
        }
    }

    record(data: recordDataType) {
        this.recordData.push(data);
    }

    getRecordIdx() {
        return this.recordData.length - 1;
    }

    fixRecordByIdx(idx: number, data: k_v<any>) {
        this.recordData[idx] = Object.assign(this.recordData[idx], data);
        // this.recordData[idx].targets = targets;
    }

    recordStatistics(role: FightObj, key: 'hit' | 'def', val: number) {
        if (!this.fightStatistics[role.rid]) this.fightStatistics[role.rid] = {};
        if (!this.fightStatistics[role.rid][key]) this.fightStatistics[role.rid][key] = 0;
        this.fightStatistics[role.rid][key] += val;
    }

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

    getResult(): fightResult {
        return {
            winSide: this.winSide,
            fightLog: this.recordData,
            initData: this.initial,
            fightData: this.DATA,
            totalDamage: this.totalDamage,
            fightStatistics: this.fightStatistics
        };
    }
}

