import { MemComBtlTeam } from './../../../domain/battleField/ComBattleTeamField';
import { difference } from 'underscore';
/*
 * @Author: 梁桐川 
 * @Date: 2020-11-30 15:05:48 
 * @Last Modified by: 梁桐川
 * @Last Modified time: 2021-03-10 20:15:30
 */
import { IT_TYPE, CURRENCY_BY_TYPE, CURRENCY_TYPE, COM_TEAM_STATUS, COM_BTL_CONST, CONSUME_TYPE, COM_BTL_QUALITY, MSG_SOURCE, QUALITY_TYPE, ROLE_SELECT, TASK_TYPE } from './../../../consts';
import Role, { RoleModel } from '../../../db/Role';
import { STATUS } from '../../../consts/statusCode';
import { Application, BackendSession } from 'pinus';
import { resResult, getRandSingleEelm } from '../../../pubUtils/util';
import { RoleStatus, ComBattleTeamModel, ComBattleTeamType, BossHp } from '../../../db/ComBattleTeam';
import { ItemModel, ItemType } from '../../../db/Item';
import { addItems, handleCost } from '../../../services/rewardService';
import { checkRoleInQueue, rmRoleFromQueue, setTeamSearchReq } from '../../../services/redisService';
import { getRandBlueprtId, clearComBtlTimer, getFrd, updateRobotHurtByTime, comBtlLvInvalid, clearRobotHurtTimer, setDismissTimer, dismissTeam, incEquipPrintDrop, randEquipPrintId, handleComBtlProgress, getComBattleFriendAdd, teammateInBlackList, blueprtIdValid, createComTeamData, hasEnoughBlueprt, addRoleToTeam, addRoleStToTeam, addValidSearchingRoles, validToJoin, addRobotsToTeam, addRobotsLater, teamIsFullToStart, oneTeamNotInBlack, getAllAssistCnt } from '../../../services/comBattleService';
import { setAp } from '../../../services/actionPointService';
import { roleLevelup } from '../../../services/normalBattleService';
import { addUserToChannel, getSimpleRoleInfo } from '../../../services/roleService';
import { ChannelUser } from '../../../domain/ChannelUser';
import { pushComBtlTeamMsg, pushFriendTeamInviteMsg, pushNormalItemMsg, pushTeamInviteMsg } from '../../../services/chatService';
import { EXTERIOR } from '../../../pubUtils/dicParam';
import { getZeroPointD, getTimeFunD } from '../../../pubUtils/timeUtil';
import { FriendParams } from '../../../domain/roleField/friend';
import { checkTask, checkTaskWithGoods } from '../../../services/taskService';
import { gameData, getWarByBlueprtId } from '../../../pubUtils/data';

export default function(app: Application) {
    return new ComBattleHandler(app);
}
export class ComBattleHandler {
    constructor(private app: Application) {
    }
    private teamMap: Map<string, MemComBtlTeam> = new Map();
    private teamDisTimer: Map<string, NodeJS.Timer> = new Map();
    private robotHurtTimer: Map<string, NodeJS.Timer> = new Map();

    /**
     * @description 队长创建队伍
     * @param {{blueprtId: number, pub: boolean, ceLimit: number}} msg 藏宝图Id，是否公开，战力限制
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async createTeam(msg: {blueprtId: number, pub: boolean, ceLimit: number}, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');
        let teamCode = session.get('teamCode');
        const { blueprtId, pub, ceLimit } = msg;

        console.log('createTeam msg: ', msg);
        // 检查藏宝图Id是否合法
        if (!blueprtIdValid(blueprtId)) return resResult(STATUS.COM_BATTLE_BLUEPRT_INVALID);
        const enoughBlueprt = await hasEnoughBlueprt(roleId, blueprtId);
        if (!enoughBlueprt) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_ENOUGH);

        const roleInfo = await RoleModel.findByRoleId(roleId, null, true);
        const { lv } = roleInfo;
        if (lv < COM_BTL_CONST.ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);

        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, true);

        // 创建队伍数据结构
        let comTeam: MemComBtlTeam = createComTeamData(teamCode, pub, blueprtId, roleId, ceLimit);
        addRoleToTeam(comTeam, roleInfo, true, false);
        addUserToChannel(channel, new ChannelUser(roleId, sid));
        // 将正在匹配的符合要求的玩家加入队伍，并推送入队消息
        await addValidSearchingRoles(comTeam, channelService);

        // 队伍数据持久化
        const team = await ComBattleTeamModel.createTeam(comTeam);
        if (!team) {
            channel.destroy();
            return resResult(STATUS.COM_BATTLE_CREATE_ERR);
        }
        this.teamMap.set(teamCode, comTeam);

        // 倒计时一定时间给队长匹配机器人
        if (pub === true) {
            await addRobotsLater(comTeam, roleInfo, this.teamMap, this.teamDisTimer, channel);
        }
        setDismissTimer(comTeam, this.teamMap, roleId, this.teamDisTimer, channel);
        return resResult(STATUS.SUCCESS, { teamCode, roleStatus: comTeam.roleStatus });
    }

    /**
     * @description 匹配队伍
     * @param {{qualityArr: [number]}} msg 要匹配的品质数组列表
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async searchTeam(msg: {qualityArr: [number], lvRange: number}, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');
        const { qualityArr, lvRange = 1 } = msg;
        const roleInfo = await RoleModel.findByRoleId(roleId, null, true);
        const { lv } = roleInfo;
        let { topLineupCe = 1000 } = roleInfo;

        if (comBtlLvInvalid(lv, lvRange)) {
            return resResult(STATUS.COM_BATTLE_ASSIST_LV_NOT_ENOUGH);
        }
        if (difference(qualityArr, COM_BTL_QUALITY).length !== 0) {
            return resResult(STATUS.COM_BLUEPRT_QUALITY_ERROR);
        }

        const teams = await ComBattleTeamModel.getOtherTeamByQualityAndSt(roleId, qualityArr, COM_TEAM_STATUS.DEFAULT, lvRange, topLineupCe);
        const team: ComBattleTeamType = await oneTeamNotInBlack(teams, roleId);
        if (team && team.roleIds.length < 3 && team.status === COM_TEAM_STATUS.DEFAULT && team.roleIds.indexOf(roleId) === -1) {
            return resResult(STATUS.SUCCESS, {teamCode: team.teamCode});
        }

        let teamCode = session.get('teamCode');
        await setTeamSearchReq(roleId, sid, qualityArr, lvRange);
        let thiz = this;
        // 倒计时匹配两个机器人
        setTimeout(async () => {
            let inQueue = await checkRoleInQueue(roleId, sid, qualityArr, lvRange);
            if (!inQueue) return;
            await rmRoleFromQueue(roleId, sid, qualityArr, lvRange);
            // 创建队伍
            let blueprtId = getRandBlueprtId(qualityArr).pop();
            let comTeam: MemComBtlTeam = createComTeamData(teamCode, false, blueprtId, 'robot', 0)

            let { quality } = gameData.goods.get(blueprtId);
            let isFrd = await getFrd(roleId, quality);
            // 将玩家加入队伍
            addRoleToTeam(comTeam, roleInfo, false, isFrd);
            let channelService = thiz.app.get('channelService');
            let channel = channelService.getChannel(teamCode, true);
            addUserToChannel(channel, new ChannelUser(roleId, sid));

            // 创建并添加机器人
            await addRobotsToTeam(comTeam, roleId, topLineupCe, lv, thiz.teamMap, thiz.teamDisTimer, channel, 2);

            await ComBattleTeamModel.createTeam(comTeam);
            thiz.teamMap.set(teamCode, comTeam);
            // 机器人队伍 3 秒直接开战
            setTimeout(async () => {
                thiz.startBattle({teamCode}, session);
            }, 3000);
        }, COM_BTL_CONST.ASSIST_TIME);
        return resResult(STATUS.SUCCESS);
    }

    /**
     * @description 取消匹配
     * @param {{}} msg
     * @param {BackendSession} session
     * @memberof ComBattleHandler
     */
    async cancelSearch(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');

        await rmRoleFromQueue(roleId, sid, COM_BTL_QUALITY, null);
        return resResult(STATUS.SUCCESS);
    }

    /**
     * @description 当匹配 searchTeam 匹配到其它队伍时，需要调用此接口加入
     * @param {{teamCode: string, isFrd: boolean}} msg 要加入的队伍编号，是否情谊助战
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async joinTeam(msg: {teamCode: string, isFrd: boolean}, session: BackendSession) {
        let roleId = session.get('roleId');
        let roleName = session.get('roleName');
        let sid = session.get('sid');
        let { teamCode, isFrd } = msg;
        let teamStatus = this.teamMap.get(teamCode);
        if (!teamStatus || teamStatus.status !== COM_TEAM_STATUS.DEFAULT) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
        if (teamIsFullToStart(teamStatus)) return resResult(STATUS.COM_BATTLE_MEMBER_LIMIT);
        if (teamStatus.roleIds.indexOf(roleId) !== -1) return resResult(STATUS.COM_BATTLE_DUP_ENTER);
        let { lv = 1, head = EXTERIOR.EXTERIOR_FACE, topLineupCe = 0, frame = EXTERIOR.EXTERIOR_FACECASE, spine = EXTERIOR.EXTERIOR_APPEARANCE } = await Role.findByRoleId(roleId, null, true);

        let { quality } = gameData.goods.get(teamStatus.blueprtId);
        if (lv < COM_BTL_CONST.ENABLE_LV) {
            return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
        } else if (comBtlLvInvalid(lv, teamStatus.lvRange)) {
            return resResult(STATUS.COM_BATTLE_ASSIST_LV_NOT_ENOUGH);
        } else if (topLineupCe < teamStatus.ceLimit) {
            return resResult(STATUS.COM_BATTLE_CE_LIMIT);
        }

        if (!isFrd) {
            isFrd = await getFrd(roleId, quality);
        }

        // 加入队伍
        if (!validToJoin(teamStatus, roleId)) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
        let roleStatus = new RoleStatus(roleId, roleName, false, isFrd, head, frame, spine, topLineupCe, lv);
        const team = await ComBattleTeamModel.addRole(teamCode, roleStatus);
        if (!team) {
            return resResult(STATUS.COM_BATTLE_JOIN_ERR);
        }

        addRoleStToTeam(teamStatus, roleStatus);

        // 推送队伍信息给所有玩家
        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, false);
        addUserToChannel(channel, new ChannelUser(roleId, sid));
        channel.pushMessage('onTeamJoin', resResult(STATUS.SUCCESS, {teamInfo: teamStatus}));

        setDismissTimer(teamStatus, this.teamMap, roleId, this.teamDisTimer, channel);
        return resResult(STATUS.SUCCESS, { teamInfo: teamStatus});
    }

    /**
     * @description 设置是否情谊助战
     * @param {{teamCode: string, isFrd: boolean}} msg 队伍编号；情谊助战要设置的值，true 为情谊助战
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async setFrdAssistance(msg: {teamCode: string, isFrd: boolean}, session: BackendSession) {
        let roleId = session.get('roleId');
        let { isFrd, teamCode } = msg;
        const isFrdPre = isFrd;
        let teamStatus = this.teamMap.get(teamCode);
        if (!teamStatus || teamStatus.status !== COM_TEAM_STATUS.DEFAULT) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
        if (teamStatus.capId === roleId) return resResult(STATUS.COM_BATTLE_SET_FRD_ERR);
        if (!isFrd) {
            isFrd = await getFrd(roleId, teamStatus.quality);
        }
        if (isFrd !== isFrdPre) {
            return resResult(STATUS.COM_BATTLE_ASSIST_NOT_ENOUGH);
        }
        teamStatus.roleStatus.forEach(async st => {
            st.isFrd = isFrd;
            await ComBattleTeamModel.updateRoleStFrd(teamCode, roleId, isFrd);
        });
        return resResult(STATUS.SUCCESS, { teamCode, isFrd });
    }

    /**
     * ! 获取队伍列表-deprecated
     * @param msg 
     * @param session 
     */
    async getTeams(msg: { blueprtIds: number[] }, session: BackendSession) {
        let roleId = session.get('roleId');
        let { lv } = await Role.findByRoleId(roleId);
        if (lv < COM_BTL_CONST.ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
        const teams = await ComBattleTeamModel.getTeamByBlueprt(msg.blueprtIds, COM_TEAM_STATUS.DEFAULT, true);
        if (!teams) return resResult(STATUS.COM_BATTLE_NO_VALID_TEAM);
        return resResult(STATUS.SUCCESS, { teamInfos: teams});
    }

    /**
     * ! deprecate
     * @description 队伍准备
     * @param {{teamCode: string, heroes: number[]}} msg
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async teammateReady(msg: {teamCode: string, heroes: number[]}, session: BackendSession) {
        let roleId = session.get('roleId');
        let { teamCode, heroes } = msg;
        let teamStatus = this.teamMap.get(teamCode);
        if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);

        let team = await ComBattleTeamModel.updateHeroes(teamCode, roleId, heroes);
        if (!team) return resResult(STATUS.COM_BATTLE_UPDATE_HEROES_ERR);

        teamStatus.roleStatus.forEach(st => {
            if (st && st.roleId === roleId) {
                st.heroes = heroes;
            }
        });

        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, false);
        channel.pushMessage('onTeammateReady', resResult(STATUS.SUCCESS, {teamCode, roleId, heroes}));
        return resResult(STATUS.SUCCESS);
    }

    /**
     * @description 出兵时记录玩家阵容
     * @param {{teamCode: string, heroes: number[]}} msg 队伍编号；阵容
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async setupHeroes(msg: {teamCode: string, heroes: number[], battleCode: string}, session: BackendSession) {
        let roleId = session.get('roleId');
        let { teamCode, heroes, battleCode = 'default' } = msg;
        if (!heroes || heroes.length === 0) return resResult(STATUS.COM_BATTLE_HEROES_ERR);
        let teamStatus = this.teamMap.get(teamCode);
        if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);

        let team = await ComBattleTeamModel.setupBattleInfo(teamCode, roleId, heroes, battleCode);
        if (!team) return resResult(STATUS.COM_BATTLE_UPDATE_HEROES_ERR);

        teamStatus.roleStatus.forEach(st => {
            if (st && st.roleId === roleId) {
                st.heroes = heroes;
                st.battleCode = battleCode;
            }
        });

        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, false);
        channel.pushMessage('onTeammateReady', resResult(STATUS.SUCCESS, {teamCode, roleId, heroes}));
        return resResult(STATUS.SUCCESS);
    }

    /**
     * @description 从队伍中移除玩家
     * @param {{teamCode: string, roleIdToRm: string}} msg 队伍编号；要移除的玩家 Id
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async rmTeammate(msg: {teamCode: string, roleIdToRm: string}, session: BackendSession) {
        let roleId = session.get('roleId');
        let { teamCode, roleIdToRm } = msg;
        let teamStatus = this.teamMap.get(teamCode);
        if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
        if (roleId === teamStatus.capId && roleId === roleIdToRm) return resResult(STATUS.COM_BATTLE_RM_SELF); // 队长移除自己视为解散，提示确认
        // if (roleId !== teamStatus.capId && roleId !== roleIdToRm) return resResult(STATUS.COM_BATTLE_CAN_NOT_RM);
        if (roleId !== teamStatus.capId) return resResult(STATUS.COM_BATTLE_CAP_ONLY); // 只有队长可以移除玩家

        // 移除操作
        let team = await ComBattleTeamModel.removeRole(teamCode, roleIdToRm);
        if (!team) return resResult(STATUS.COM_BATTLE_RM_TEAMMATE_ERR);

        let roleIdx = teamStatus.roleIds.indexOf(roleIdToRm);
        teamStatus.roleIds.splice(roleIdx, 1);

        teamStatus.roleStatus.some((elem, idx) => {
            if (elem.roleId === roleIdToRm) {
                teamStatus.roleStatus.splice(idx, 1);
            }
        });

        // 推送移除消息
        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, false);
        // 先推送离队消息，再将玩家从房间中移除
        channel.pushMessage('onLeaveTeam', resResult(STATUS.SUCCESS, {teamCode, roleId: roleIdToRm}));
        let users: string[] = channel.getMembers();
        if (users.indexOf(roleIdToRm) !== -1) {
            channel.removeMember(roleIdToRm);
        }
        clearComBtlTimer(teamCode, this.teamDisTimer); // 移除队员停止解散计时
        let thiz = this;
        setTimeout(async () => {
            let curTeamStatus = thiz.teamMap.get(teamCode);
            if (validToJoin(curTeamStatus)) {
                let roleSt: RoleStatus;
                for (let st of curTeamStatus.roleStatus) {
                    if (st.roleId === roleId) {
                        roleSt = st;
                    }
                }
                if (!roleSt) return;
                let { topLineupCe, lv } = roleSt;
                await addRobotsToTeam(curTeamStatus, roleId, topLineupCe, lv, thiz.teamMap, thiz.teamDisTimer, channel, 3 - curTeamStatus.roleIds.length);
            }
        }, COM_BTL_CONST.ASSIST_TIME);
        return resResult(STATUS.SUCCESS);
    }

    /**
     * @description 队长解散队伍
     * @param {{teamCode: string}} msg 要解散的队伍编号
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async dismiss(msg: {teamCode: string}, session: BackendSession) {
        let roleId = session.get('roleId');
        let { teamCode } = msg;
        let teamStatus = this.teamMap.get(teamCode);
        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, false);
        let result = await dismissTeam(teamStatus, this.teamMap, roleId, this.teamDisTimer, channel);
        return result;
    }

    /**
     * @description 开始战斗，队长操作或机器人队伍操作
     * @param {{teamCode: string}} msg 队伍编号
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async startBattle(msg: {teamCode: string}, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');
        let { teamCode } = msg;
        let teamStatus = this.teamMap.get(teamCode);
        if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
        if (teamStatus.capId !== roleId && teamStatus.capId !== 'robot') return resResult(STATUS.COM_BATTLE_CAP_ONLY);
        if (teamStatus.status !== COM_TEAM_STATUS.DEFAULT) return resResult(STATUS.COM_BATTLE_ALREADY_START);

        teamStatus.status = COM_TEAM_STATUS.FIGHTING;

        let team = await ComBattleTeamModel.updateStatusByCode(teamCode, COM_TEAM_STATUS.FIGHTING);
        if (!team) return resResult(STATUS.COM_BATTLE_START_ERR);

        clearComBtlTimer(teamCode, this.teamDisTimer); // 战斗开始停止解散计时
        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, false);

        await getComBattleFriendAdd(teamStatus.roleStatus);
        channel.pushMessage('onComBtlStart', resResult(STATUS.SUCCESS, {teamCode, roleStatus: teamStatus.roleStatus}));
        // 每场倒计时结算
        let thiz = this;
        setTimeout(async () => {
            let teamStatus = thiz.teamMap.get(teamCode);
            if (teamStatus && teamStatus.status === COM_TEAM_STATUS.FIGHTING) {
                clearRobotHurtTimer(teamStatus, this.robotHurtTimer);
                let channelService = thiz.app.get('channelService');
                let channel = channelService.getChannel(teamCode, false);
                let team = await ComBattleTeamModel.syncTeamData({teamCode, status: COM_TEAM_STATUS.LOOSE, roleStatus: teamStatus.roleStatus, bossHpArr: teamStatus.bossHpArr}, true);
                if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
                teamStatus.timeout = true;
                channel.pushMessage('onTeamComplete', resResult(STATUS.SUCCESS, {teamCode, result: false, timeout: true}));
                thiz.teamMap.delete(teamCode);
            }
        }, COM_BTL_CONST.BTL_TIME_LMT);
        teamStatus.roleStatus.forEach((st, idx) => {
            if (st.isRobot === true) {
                updateRobotHurtByTime(teamStatus, st, COM_BTL_CONST.ROBOT_BASE_TIME_INTERVAL + idx, channel, this.robotHurtTimer, this.teamMap);
            }
        });
        return resResult(STATUS.SUCCESS);
    }

    /**
     * @description 战场中的状态同步，战斗结果判定
     * @param {{teamCode: string, bossHurts: Array<{dataId: number, hurtHp: number}>, killed: number[], curRnd: number}} msg 队伍编号；boss 承伤；武将阵亡；当前回合
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async action(msg: {teamCode: string, bossHurts: Array<{dataId: number, hurtHp: number}>, killed: number[], curRnd: number}, session: BackendSession) {
        let roleId = session.get('roleId');
        let { teamCode, killed, bossHurts, curRnd } = msg;
        let teamStatus = this.teamMap.get(teamCode);
        if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
        if (teamStatus.status !== COM_TEAM_STATUS.FIGHTING) return resResult(STATUS.COM_BATTLE_NOT_START);
        for (let st of teamStatus.roleStatus) {
            if (st.roleId === roleId && (!st.heroes || st.heroes.length === 0)) {
                return resResult(STATUS.COM_BATTLE_HEROES_ERR);
            }
        }
        // 重置总血量，计算真实伤害
        let actBossHurts: {dataId: number, hurtHp: number}[] = [];
        let totalHurtHp = 0;
        teamStatus.bossHpArr.forEach(boss => {
            for (let bh of bossHurts) {
                if (boss.dataId === bh.dataId && bh.hurtHp < 0) {
                    let deltaHp = Math.abs(bh.hurtHp);
                    if (boss.curHp >= deltaHp) {
                        actBossHurts.push({dataId: boss.dataId, hurtHp: deltaHp});
                        totalHurtHp += deltaHp;
                        boss.curHp -= deltaHp;
                    } else if (boss.curHp > 0) {
                        actBossHurts.push({dataId: boss.dataId, hurtHp: boss.curHp});
                        totalHurtHp += boss.curHp;
                        boss.curHp = 0;
                    }
                }
            }
        });
        // 更新玩家武将阵亡情况，计算玩家总伤害
        const roleSt = teamStatus.roleStatus.find(st => st.roleId === roleId);
        roleSt.totalDmg += totalHurtHp;
        if (killed && killed.length) {
            roleSt.killed = Array.from(new Set([...roleSt.killed, ...killed]));
        }

        teamStatus.curRnd = curRnd;
        teamStatus.bossCurHp -= totalHurtHp;
        if (teamStatus.bossCurHp < 0) teamStatus.bossCurHp = 0;
        // 推送本次行动情况
        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, false);
        const roleStatus = teamStatus.roleStatus.map(st => {return {roleId: st.roleId, totalDmg: st.totalDmg, killed: st.killed}});
        channel.pushMessage('onTeammateAct', resResult(STATUS.SUCCESS, { teamCode, bossCurHp: teamStatus.bossCurHp, bossHpArr: teamStatus.bossHpArr, roleStatus, actRoleId: roleId, actBossHurts }));
        const result = await handleComBtlProgress(teamStatus, this.robotHurtTimer, this.teamMap, channel);
        if (result && result.code !== 0) return result;
        return resResult(STATUS.SUCCESS);
    }

    /**
     * ! 客户端给服务器的战斗结束通知-deprecated
     * @param msg 
     * @param session 
     */
    async battleEnd(msg: {teamCode: string, isSuccess: boolean}, session: BackendSession) {
        let roleId = session.get('roleId');
        let { teamCode, isSuccess } = msg;
        let teamStatus = this.teamMap.get(teamCode);
        if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);

        let channelService = this.app.get('channelService');
        let channel = channelService.getChannel(teamCode, false);
        if (isSuccess && teamStatus.bossCurHp <= 0) {
            let team = await ComBattleTeamModel.updateResult(teamCode, roleId, isSuccess);
            if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
            channel.pushMessage('onTeamComplete', resResult(STATUS.SUCCESS, {teamCode, result: isSuccess}));
        } else if (!isSuccess) {
            let team = await ComBattleTeamModel.updateResult(teamCode, roleId, isSuccess);
            if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
            if (team.status === COM_TEAM_STATUS.LOOSE) {
                channel.pushMessage('onTeamComplete', resResult(STATUS.SUCCESS, {teamCode, result: isSuccess}));
            } else {
                channel.pushMessage('onTeammateAct', resResult(STATUS.SUCCESS, {teamCode, bossCurHp: teamStatus.bossCurHp, roleStatus: {roleId, battleStatus: 2}}));
            }
        }
        return resResult(STATUS.SUCCESS, { bossCurHp: teamStatus.bossCurHp });
    }

    /**
     * @description 寻宝结算
     * @param {{teamCode: string}} msg 寻宝队伍编号
     * @param {BackendSession} session
     * @returns 掉落物品和玩家升级信息
     * @memberof ComBattleHandler
     */
    async comBattleEnd(msg: {teamCode: string}, session: BackendSession) {
        let roleId = session.get('roleId');
        let roleName = session.get('roleName');
        let sid = session.get('sid');
        const funcs: number[] = session.get('funcs');
        let { teamCode } = msg;
        let team = await ComBattleTeamModel.getTeamByCode(teamCode);
        clearRobotHurtTimer(team, this.robotHurtTimer);
        if (!team || team.status !== COM_TEAM_STATUS.WIN) return resResult(STATUS.COM_BATTLE_REWARD_ERR);
        let { roleStatus, blueprtId, status, bossHpArr } = team;
        let roleSt: RoleStatus = null;
        roleStatus.forEach(st => {
            if (st && st.roleId === roleId) {
                roleSt = st;
            }
        });
        if (roleSt.gotReward) return resResult(STATUS.COM_BATTLE_REWARDED);
        let warInfo = getWarByBlueprtId(blueprtId);
        if (!warInfo) return resResult(STATUS.BATTLE_MISS_INFO);

        let role = await RoleModel.findByRoleId(roleId, 'lv');
        let apJson = await setAp(roleId, role.lv, -1 * warInfo.cost, sid, funcs); // 扣除体力
        if(!apJson) {
            return resResult(STATUS.BATTLE_ACTION_POINT_LACK);
        }

        const { dropResult } = await incEquipPrintDrop(roleSt);
        if (dropResult) {
            const dropEquipId = randEquipPrintId(warInfo);
            if (dropEquipId) {
                roleSt.fixReward.push({ id: dropEquipId, count: 1 });
            }
        }

        await ComBattleTeamModel.updateRewardSt(teamCode, roleId, true);
        const goods = await addItems(roleId, roleName, sid, roleSt.fixReward);
        let actordata = await roleLevelup(roleId, warInfo.kingExp, session);// 主公升级经验
        // 任务
        await checkTaskWithGoods(roleId, sid, funcs, TASK_TYPE.COM_BATTLE_DROP, goods);

        return resResult(STATUS.SUCCESS, { battleGoods: goods, ...actordata, teamInfo: {status, teamCode, roleStatus, bossHpArr} });
    }

    async getComBtlStatus(msg: {teamCode: string}, session: BackendSession) {
        let { teamCode } = msg;
        let roleStatus: RoleStatus[], status: number, bossHpArr: BossHp[], timeout: boolean;
        let memTeam = this.teamMap.get(teamCode);
        if (memTeam) {
            ({ roleStatus, status, bossHpArr, timeout } = memTeam);
        } else {
            let dbTeam = await ComBattleTeamModel.getTeamByCode(teamCode);
            if (!dbTeam) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
            ({ roleStatus, status, bossHpArr, timeout } = dbTeam);
        }
        return resResult(STATUS.SUCCESS, { teamInfo: {status, teamCode, roleStatus, bossHpArr, timeout} });
    }

    /**
     * @description 获取自己一段时间内的寻宝记录
     * @param {{}} msg
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async getTeamRec(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let timef = getTimeFunD();
        let teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, null, <Date>timef.getBeforeDayWithHour(2));
        if (!teams) return resResult(STATUS.COM_BATTLE_NO_RECENT_REC);

        return resResult(STATUS.SUCCESS, {teamInfos: teams});
    }

    /**
     * @description 获取藏宝图数量
     * @param {{ids: number[]}} msg 藏宝图Id数组，可选参数
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async getBlueprtCount(msg: {ids: number[]}, session: BackendSession) {
        let roleId = session.get('roleId');
        let { ids } = msg;
        let blueprts: ItemType[];
        if (ids && ids.length) {
            blueprts = await ItemModel.findbyRoleAndIds(roleId, ids);
        } else {
            blueprts = await ItemModel.findByRoleAndType(roleId, CONSUME_TYPE.BLUEPRT);
        }
        return resResult(STATUS.SUCCESS, { blueprts });
    }

    /**
     * @description 获取今日已助战次数
     * @param {{}} msg
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async getAssistCnt(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let cnt = await getAllAssistCnt(roleId);
        return resResult(STATUS.SUCCESS, {cnt});
    }
    /**
     * @description 获取寻宝可用次数，包含藏宝图数量和助战次数，分别用于创建和加入队伍
     * @param {{}} msg 无参数
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async getComBtlCnt(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let cnt = await getAllAssistCnt(roleId);
        const blueprts = await ItemModel.findByRoleAndType(roleId, CONSUME_TYPE.BLUEPRT);
        return resResult(STATUS.SUCCESS, { blueprts, assistCnt: cnt });
    }

    async sendTeamMsg(msg: { teamCode: string, type: number, content: string, targetRoleId: string, targetMsgCode: string }, session: BackendSession) {
        let roleId = session.get('roleId');
        let roleName = session.get('roleName');

        const { teamCode, type, content, targetRoleId, targetMsgCode } = msg;
        const result = await pushComBtlTeamMsg(teamCode, roleId, roleName, type, MSG_SOURCE.TEAM_ROLE, content, targetRoleId, targetMsgCode);
        if (!result) {
            return resResult(STATUS.WRONG_PARMS);
        }
        return resResult(STATUS.SUCCESS);
    }

    /**
     * @description 一键邀请，自动在世界频道发送消息
     * @param {{ teamCode: string }} msg
     * @param {BackendSession} session
     * @memberof ComBattleHandler
     */
    async autoInvite(msg: { teamCode: string }, session: BackendSession) {
        let roleId = session.get('roleId');
        let roleName = session.get('roleName');
        let serverId = session.get('serverId');
        const { teamCode } = msg;
        const { msgDataWorld, msgDataGuild } = await pushTeamInviteMsg(roleId, roleName, serverId, teamCode);
        if (!msgDataWorld || !msgDataGuild) return resResult(STATUS.WRONG_PARMS);
        return resResult(STATUS.SUCCESS);
    }

    /**
     * @description 邀请队友
     * @param {{ teamCode: string, targetRoleId: string }} msg
     * @param {BackendSession} session
     * @memberof ComBattleHandler
     */
    async inviteTeammate(msg: { teamCode: string, targetRoleId: string }, session: BackendSession) {
        let roleId = session.get('roleId');
        let roleName = session.get('roleName');
        const { teamCode, targetRoleId } = msg;
        const msgData = await pushFriendTeamInviteMsg(roleId, roleName, teamCode, targetRoleId);
        if (!msgData) return resResult(STATUS.WRONG_PARMS);
        const roleInfo = await getSimpleRoleInfo(targetRoleId);

        return resResult(STATUS.SUCCESS, {...msgData, roleInfo});
    }

    /**
     * @description 最近组队过的队友列表
     * @param {} msg 
     * @param {BackendSession} session 
     */
    async getRecentTeammates(msg: { }, session: BackendSession) {
        let roleId = session.get('roleId');

        const teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, null, getZeroPointD());
        let roleIdList = new Array<string>();
        for(let { roleIds } of teams) {
            for(let r of roleIds) {
                if(r != roleId) roleIdList.push(r);
            }
        }
        const roles = await RoleModel.findRoleByField('roleId', roleIdList, ROLE_SELECT.SHOW_SIMPLE, true);
        let result = new Array<FriendParams>();
        for(let role of roles) {
            if(role.quitTime == role.loginTime) {
                let r = new FriendParams(role);
                result.push(r);
            }
        }

        return resResult(STATUS.SUCCESS, { list: result });
    }

    /**
     * @description 藏宝图合成
     * @param {{original: Array<{id: number, count: number}>}} msg
     * @param {BackendSession} session
     * @returns
     * @memberof ComBattleHandler
     */
    async composeBlueprt(msg: {original: Array<{id: number, count: number}>}, session: BackendSession) {
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const sid = session.get('sid');
        const serverId = session.get('serverId');
        const funcs: number[] = session.get('funcs');
        
        const { original } = msg;

        // 原材料检查
        let originalQuality: number, originalSum: number = 0;
        for(let {id, count} of original) {
            const goodInfo = gameData.goods.get(id);
            if(!originalQuality) originalQuality = goodInfo.quality;
            if(originalQuality != goodInfo.quality) {
                return resResult(STATUS.COM_BLUEPRT_QUALITY_ERROR);
            }

            if(goodInfo.itid == IT_TYPE.BLUEPRT) {
                originalSum += count;
            }
        }

        const dicCompose = gameData.blurprtCompose.get(originalQuality);
        if(!dicCompose) {
            return resResult(STATUS.COM_BLUEPRT_QUALITY_CANNOT_COMPOSE);
        } 
        if(originalSum != dicCompose.blueprtNum) {
            return resResult(STATUS.COM_BLUEPRT_COUNT_ERROR);
        }
        // 添加寻宝币
        original.push({
            id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.TREASURE_POINT),
            count: dicCompose.coinNum
        });
        // 消耗藏宝图和寻宝币

        let costResult = await handleCost(roleId, sid, original);
        if(!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH);

        const targetList = gameData.blueprt.get(dicCompose.targetQuality);
        const target = getRandSingleEelm(targetList);
        const reward = [{id: target, count: 1}];
        const goods = await addItems(roleId, roleName, sid, reward);
        if (dicCompose.targetQuality >= QUALITY_TYPE.ORANGE) {
            const { name } = gameData.goods.get(target);
            pushNormalItemMsg(roleId, roleName, serverId, MSG_SOURCE.ORANGE_BLUEPRT_COMPOSE, target, name);
        }
        await checkTask(roleId, sid, funcs, TASK_TYPE.COM_BATTLE_BLUEPRT, 1, true, { quality: dicCompose.targetQuality });
        
        return resResult(STATUS.SUCCESS, { goods, costGold: 0 });
    }
}
