import { WAR_TYPE } from './../../../consts/constModules/battleConst';

import { Application, BackendSession, pinus, HandlerService, } from 'pinus';
import { findIndex } from 'underscore';
import { gameData, getPvpBoxBySeasonNumAndIndex } from '../../../pubUtils/data';
import { refreshEnemies, getEnemies, refChallengeCnt, generPVPOppRecInfo, generMyRecInfo, sendLastSeasonRewardIfNotSent, refreshRefOppCnt, generPvpLineupCe, calLineupScore, checkPvpSeasonIsStart, checkPvpSeasonIsSummit, getPvpSeasonStatus, checkPvpSeasonIsWaiting } from '../../../services/pvpService';
import { RoleModel, RoleType } from '../../../db/Role';
import { STATUS } from '../../../consts/statusCode';
import { resResult, genCode, checkRoleIsRobot, robotIdComBack } from '../../../pubUtils/util';
import { PvpDefenseModel, pvpUpdateInter } from '../../../db/PvpDefense';
import { PvpSeasonResultModel } from '../../../db/PvpSeasonResult';
import { Rank } from '../../../services/rankService';
import { checkTask, checkTaskInPvpEnd } from '../../../services/task/taskService';
import { Attack, Defense, DefenseHero, PvpDataReturn, pvpSaveDataReturn } from '../../../domain/battleField/pvp';
import { DEBUG_MAGIC_WORD, FIGURE_UNLOCK_CONDITION, ITEM_CHANGE_REASON, LINEUP_NUM, REDIS_KEY, TASK_TYPE } from '../../../consts';
import { PVP } from '../../../pubUtils/dicParam';
import { addItems, getGoldObject, handleCost, unlockFigure } from '../../../services/role/rewardService';
import { pick } from "underscore";
import { HeroModel } from '../../../db/Hero';
import PvpHistoryOpp, { PvpHistoryOppModel } from '../../../db/PvpHistoryOpp';
import { BattleRecordModel } from '../../../db/BattleRecord';
import { PvpRecordModel, PvpRecordParam, PvpRecordType } from '../../../db/PvpRecord';
import { pvpEndParamInter } from '../../../pubUtils/interface';
import { getSeconds, nowSeconds } from '../../../pubUtils/timeUtil';
import { getRemoteRplPrefix, getRemoteRplFilePath } from '../../../pubUtils/battleUtils';
import { PlayerDetail, PlayerDetailHero } from '../../../domain/battleField/guild';
import { PvpSaveDataModel } from '../../../db/PvpSaveData';
import { PVPConfigModel } from '../../../db/PvpConfig';
import { getAllServerName, getServerName } from '../../../services/redisService';
import { RoleRankInfo } from '../../../domain/rank';
import { isHeroHidden } from '../../../services/dataService';

export default function (app: Application) {
    new HandlerService(app, {});
    return new PvpHandler(app);
}

export class PvpHandler {
    constructor(private app: Application) {
    }

    //1获取主界面
    async getData(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
 
        let seasonNum: number = this.app.get('pvpSeasonNum');
        let seasonStartTime: number = this.app.get('pvpSeasonStartTime');
        let seasonEndTime: number = this.app.get('pvpSeasonEndTime');
        let seasonRewardTime: number = this.app.get('pvpSeasonRewardTime');
        let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
        if(!pvpDefense) {
            let role = await RoleModel.findByRoleId(roleId);
            pvpDefense = await PvpDefenseModel.createPvpDefense(seasonNum, { serverId: role.serverId, roleId: role.roleId, roleName: role.roleName, role: role._id });
        } else {
            // 如果没有发过，将上赛季的奖励发下
            pvpDefense = await sendLastSeasonRewardIfNotSent(pvpDefense);
        }

        let update: pvpUpdateInter = { };
        let result = new PvpDataReturn(); // 返回对象
        // 刷新次数
        let refChallengeObj = await refChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime, roleId, session.get('vipStartTime'));
        if(refChallengeObj.hasChanged) {
            update = { ...update, ...refChallengeObj }
        }
        let refOppObj = refreshRefOppCnt(pvpDefense);
        // 每天首次打开要刷掉对手
        if(refOppObj.shouldRefOpp) {
            if(pvpDefense.attack) {
                let role = <RoleType>pvpDefense.role;
                let oppPlayers = await refreshEnemies(role, seasonNum, pvpDefense.score, pvpDefense.attack.score, pvpDefense.attack.pLv||1);
                update.oppPlayers = oppPlayers;
            }
            update = { ...update, ...refOppObj }
        }
        
        if(Object.keys(update).length > 0) {
            pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, update);
        }

        result.setPvpConfig(seasonNum, seasonStartTime, seasonEndTime, seasonRewardTime);
        result.setPvpDefense(pvpDefense);
        result.calHasSaveDefense();

        let oppPlayersReturn = await getEnemies(pvpDefense.oppPlayers||[], pvpDefense.winStreakNum);
        result.setOppPlayers(oppPlayersReturn);
        // 赛季结算
        let pvpSeasonResult = await PvpSeasonResultModel.getPvpSeasonResult(roleId);
        if (!!pvpSeasonResult && !!pvpSeasonResult.show) {
            result.setPvpSeasonResult(pvpSeasonResult);
            await PvpSeasonResultModel.setShow(roleId);
        }
        // 拍卖
        let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum });
        let myRank = await r.getMyRank({ roleId });//去redis中获取排名
        result.setMyRank(myRank);

        return resResult(STATUS.SUCCESS, result);
    }

    // 刷新对手
    async refreshOppPlayer(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');

        let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
        if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);
        if(!pvpDefense.attack) return resResult(STATUS.PVP_NOT_SET_ATTACK);

        // 刷新次数及消耗
        let refOppObj = refreshRefOppCnt(pvpDefense);
        if (refOppObj.refOppCnt >= gameData.maxPvpRefreshCnt.max) {
            return resResult(STATUS.PVP_REFRESH_CNT_REACH_MAX);
        }

        let costResult = await handleCost(roleId, sid, refOppObj.consume, ITEM_CHANGE_REASON.PVP_REFRESH_OPP);
        if (!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH);
        refOppObj.refOppCnt ++;

        // 刷新对手
        let role = <RoleType>pvpDefense.role;
        let seasonNum: number = this.app.get('pvpSeasonNum');
        let oppPlayers = await refreshEnemies(role, seasonNum, pvpDefense.score, pvpDefense.attack.score, pvpDefense.attack.pLv||1);

        pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers, ...refOppObj });

        let result = new PvpDataReturn(); // 返回对象
        result.setPvpDefense(pvpDefense);
        let oppPlayersReturn = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum);
        result.setOppPlayers(oppPlayersReturn);

        return resResult(STATUS.SUCCESS, pick(result, ['oppPlayers', 'refOppCnt', 'buyAttackCnt', 'setAttackCnt']));
    }
    
    // 获取对手阵容具体信息
    async getOppPlayer(msg: { roleId: string }, session: BackendSession) {
        let roleId = session.get('roleId');

        if(!checkPvpSeasonIsStart()) {
            return resResult(STATUS.PVP_SEASON_NOT_OPEN);
        }
        let oppoRoleId = msg.roleId;
        let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
        if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);
        let { oppPlayers } = pvpDefense;

        let curOpp = oppPlayers.find(cur => cur.roleId == oppoRoleId);
        if (!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND);

        let pvpHistoryOpp = <PvpHistoryOpp>curOpp.oppDef;

        return resResult(STATUS.SUCCESS, { roleId: pvpHistoryOpp.oppRoleId, ...pick(pvpHistoryOpp, ['pos', 'title', 'warId', 'buff', 'heroes']) });
    }

    
    // 开战
    async pvpStart(msg: { warId: number, roleId: string }, session: BackendSession) {
        const { warId, roleId: oppRoleId } = msg;
        let roleId = session.get('roleId');
        let roleName = session.get('roleName');
        let serverId = session.get('serverId');
        let sid = session.get('sid');

        let warInfo = gameData.war.get(warId);
        if (!warInfo) {
            return resResult(STATUS.BATTLE_MISS_INFO);
        }

        let pvpDefense = await PvpDefenseModel.findByRoleId(roleId);
        if (!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);
        // 检查挑战次数
        let seasonNum: number = this.app.get('pvpSeasonNum');
        let seasonEndTime: number = this.app.get('pvpSeasonEndTime');
        let { challengeCnt, challengeRefTime } = await refChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime, roleId, session.get('vipStartTime'));
        if (challengeCnt == 0) {
            return resResult(STATUS.PVP_CHALLENGE_TIMES_NOT_ENOUGH);
        }
        let curOpp = pvpDefense.oppPlayers.find(cur => cur.roleId == oppRoleId);
        if (!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND)

        const battleCode = genCode(8); // 关卡唯一值
        let heroes = pvpDefense.attack.heroes.map(cur => cur.actorId);

        await BattleRecordModel.updateBattleRecordByCode(battleCode, {
            $set: {
                roleId, roleName, battleId: warId,
                status: 0,
                warName: warInfo.gk_name,
                warType: warInfo.warType,
                record: { heroes, pos: curOpp.pos, oppRoleId, pvpSeasonNum: seasonNum }
            }
        }, true);    
        await checkTask(serverId, roleId, sid, TASK_TYPE.PVP);
        // 战报记录
        await PvpRecordModel.createRec(roleId, robotIdComBack(oppRoleId), battleCode);

        // 对手记录更新
        await PvpHistoryOppModel.setStatus(curOpp.oppDef.toString(), 1);

        let update: pvpUpdateInter = {
            oppBeforePlayers: pvpDefense.oppPlayers
        };
        // 刷新对手
        const role = await RoleModel.findByRoleId(roleId, null, true);
        let oppPlayers = await refreshEnemies(role, seasonNum, pvpDefense.score ,pvpDefense.attack.score, pvpDefense.attack.pLv||1);
        update.oppPlayers = oppPlayers;

        // 减少挑战次数
        let refChallengeObj = await refChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime, roleId, session.get('vipStartTime'));
        refChallengeObj.challengeCnt--;
        update = {...update, ...refChallengeObj};

        pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, update);

        let result = new PvpDataReturn(); // 返回对象
        result.setPvpDefense(pvpDefense);
        let oppPlayersReturn = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum);
        result.setOppPlayers(oppPlayersReturn);

        return resResult(STATUS.SUCCESS, {
            battleCode,
            ...pick(result, ['oppPlayers', 'challengeCnt', 'challengeRefTime'])
        });
    }

    // 结算
    async pvpEnd(msg: { battleCode: string, isSuccess: boolean, myHeroes: pvpEndParamInter[], oppHeroes: pvpEndParamInter[] }, session: BackendSession) {

        let roleId = session.get('roleId');
        let roleName = session.get('roleName');
        let sid = session.get('sid');
        
        const serverId = session.get('serverId');

        const { battleCode, isSuccess, myHeroes, oppHeroes } = msg;

        const BattleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode, true);
        if (!BattleRecord || BattleRecord.status != 0) {
            return resResult(STATUS.BATTLE_STATUS_WRONG);
        }

        let { record: { heroes: dbHeroes, oppRoleId, pos, pvpSeasonNum }, createdAt } = BattleRecord;

        let flag = 1; // 对比hero信息
        for (let { hid } of myHeroes) {
            if (dbHeroes.indexOf(hid) == -1) flag = 0;
        }
        if (!flag) return resResult(STATUS.BATTLE_INFO_VALIDATE_ERR);

        // 更新军功
        let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
        if (!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);
        let { hisWinStreakNum = 0 } = pvpDefense;

        let update: pvpUpdateInter = {};

        const role = await RoleModel.findByRoleId(roleId, null, true);

        const myRecInfo = await generMyRecInfo(pvpDefense, role, isSuccess, pos, myHeroes);
        let { attackInfo, showHeroScores, updateParam } = myRecInfo
        update = { ...update, ...updateParam };

        let curOpp = pvpDefense.oppBeforePlayers.find(cur => cur.roleId == oppRoleId && cur.pos == pos);
        if (!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND);
        const defenseInfo = await generPVPOppRecInfo(isSuccess, curOpp, oppHeroes, serverId);

        let seasonNum: number = this.app.get('pvpSeasonNum');
        // 战报记录
        await PvpRecordModel.updateByBattleCode(battleCode, { warId: BattleRecord.battleId, attackInfo, defenseInfo, createTime: nowSeconds(), timeout: seasonNum != pvpSeasonNum });

        // 更新battleRecord
        await BattleRecordModel.updateBattleRecordByCode(battleCode, {
            $set: { status: isSuccess ? 1 : 2 }
        }, true);

        if(seasonNum == pvpSeasonNum) {
            pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, update);
        }

        let result = new PvpDataReturn(); // 返回对象
        result.setPvpDefense(pvpDefense);
        let oppPlayersReturn = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum);
        result.setOppPlayers(oppPlayersReturn);


        if(seasonNum == pvpSeasonNum) {
            // 加入排行榜
            let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum: pvpSeasonNum });
            await r.setRankWithRoleInfo(roleId, pvpDefense.score, pvpDefense.updatedAt.getTime(), role);
            let myRank = await r.getMyRank({ roleId });
            result.setMyRank(myRank);
        }

        await checkTaskInPvpEnd(serverId, roleId, sid, isSuccess, pvpDefense.heroScores, pvpDefense.seasonWinNum);
        if(hisWinStreakNum < pvpDefense.hisWinStreakNum) {
            await unlockFigure(sid, roleId, [{ type: FIGURE_UNLOCK_CONDITION.PVP_WIN_SERIES, paramWinStreakNum: pvpDefense.hisWinStreakNum }]);
        }

        return resResult(STATUS.SUCCESS, {
            battleCode, isSuccess,
            heroScores: showHeroScores,
            createdAt: getSeconds(createdAt),
            ...pick(result, ['score', 'myRank', 'winStreakNum', 'attack', 'oppPlayers', 'challengeCnt', 'challengeRefTime', 'seasonWinNum'])
        });
    }

    async buyAttackCnt(msg: { count: number }, session: BackendSession) {
        let { count } = msg;
        let roleId = session.get('roleId');
        let sid = session.get('sid');

        let pvpDefense = await PvpDefenseModel.findByRoleId(roleId);
        if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);

        // 次数
        let refOppObj = refreshRefOppCnt(pvpDefense);
        if(refOppObj.buyAttackCnt + count > PVP.PVP_BUY_SET_ATTACK_CNT) {
            return resResult(STATUS.PVP_BUY_ATTACK_CNT_NOT_ENOUGH);
        }
        refOppObj.buyAttackCnt += count;

        let gold = getGoldObject(PVP.PVP_SET_ATTACK_CNT_GOLD * count);
        let costResult = await handleCost(roleId, sid, [gold], ITEM_CHANGE_REASON.PVP_BUY_ATTACK_CNT);
        if(!costResult) return resResult(STATUS.TOWER_GOLD_NOT_ENOUGH);

        let update: pvpUpdateInter = { ...refOppObj };

        // 更新挑战阵容
        if(refOppObj.shouldRefOpp) {
            if(pvpDefense.attack) {
                let role = await RoleModel.findByRoleId(roleId);
                let seasonNum: number = this.app.get('pvpSeasonNum');
                let oppPlayers = await refreshEnemies(role, seasonNum, pvpDefense.score, pvpDefense.attack.score, pvpDefense.attack.pLv||1);
                update.oppPlayers = oppPlayers;
            }
        }
        // 保存
        pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, update);
        // 返回
        let result = new PvpDataReturn();
        result.setPvpDefense(pvpDefense);
        let pickParam = ['buyAttackCnt', 'setAttackCnt', 'refOppCnt'];
        if(refOppObj.shouldRefOpp) {
            let oppPlayersReturn = await getEnemies(pvpDefense.oppPlayers||[], pvpDefense.winStreakNum);
            result.setOppPlayers(oppPlayersReturn);
            pickParam.push('oppPlayers');
        }

        return resResult(STATUS.SUCCESS, pick(result, pickParam));
    }

    async saveAttack(msg: { heroes: { actorId: number, order: number }[] }, session: BackendSession) {
        let { heroes } = msg;
        let roleId = session.get('roleId');
        
        let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
        if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);

        // 次数
        let refOppObj = refreshRefOppCnt(pvpDefense);
        if(refOppObj.setAttackCnt >= PVP.PVP_SET_ATTACK_FREE_CNT + refOppObj.buyAttackCnt) {
            return resResult(STATUS.PVP_SET_ATTACK_CNT_NOT_ENOUGH);
        }
        if(!!pvpDefense.attack) {
            refOppObj.setAttackCnt ++;
        }
        
        let seasonNum: number = this.app.get('pvpSeasonNum');
        let seasonEndTime: number = this.app.get('pvpSeasonEndTime');
        let refChallengeObj = await refChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime, roleId, session.get('vipStartTime'));
        // 更新挑战阵容
        let scores: number[] = [];
        for(let { actorId } of heroes) {
            if(isHeroHidden(actorId)) return resResult(STATUS.HERO_IS_HIDDEN);
            let heroScore = pvpDefense.heroScores.find(cur => cur.hid == actorId);
            if(heroScore) {
                scores.push(heroScore.score);
            }
        }
        let attack = new Attack(heroes, scores);
        let lineupCe = await generPvpLineupCe(roleId, pvpDefense.lineupCe, attack.heroes, pvpDefense.defense?.heroes??[], []);
        // 刷对手
        let role = <RoleType>pvpDefense.role;
        let oppPlayers = await refreshEnemies(role, seasonNum, pvpDefense.score, attack?.score||0, attack?.pLv||1);
        // 保存
        pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { ...refOppObj, ...refChallengeObj, attack, oppPlayers, lineupCe });
        // 返回
        let result = new PvpDataReturn();
        result.setPvpDefense(pvpDefense);
        let oppPlayersReturn = await getEnemies(pvpDefense.oppPlayers||[], pvpDefense.winStreakNum);
        result.setOppPlayers(oppPlayersReturn);

        return resResult(STATUS.SUCCESS, pick(result, ['attack', 'oppPlayers', 'buyAttackCnt', 'setAttackCnt', 'challengeCnt', 'challengeRefTime']));
    }

    // 获取存档列表
    async getSaveData(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let pvpDefense = await PvpDefenseModel.findByRoleId(roleId);
        if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);

        let pvpConfig = await PVPConfigModel.findCurPVPConfig();
        if(!pvpConfig) return resResult(STATUS.PVP_SEASON_NOT_OPEN);

        let saveDatas = await PvpSaveDataModel.findByRoleId(roleId);

        let list: pvpSaveDataReturn[] = [];
        for(let warId of (pvpConfig.warIds||[])) {
            let dicWar = gameData.war.get(warId);
            if(dicWar && dicWar.selectView == 1) {
                let data = new pvpSaveDataReturn(warId);
                let curSaveData = saveDatas.find(cur => cur.warId == warId);
                data.setUserSaveData(curSaveData);
                if(pvpDefense.defense?.warId == warId) {
                    data.setAsUsing();
                }
                list.push(data);
            }
        }
        return resResult(STATUS.SUCCESS, { list });
    }

    //3. 保存防守阵容
    async saveDefense(msg: { heroes: { actorId: number, dataId: number, order: number, ai: number }[], warId: number, buff: number }, session: BackendSession) {
        let { heroes, warId, buff } = msg;
        let roleId = session.get('roleId');
        if (heroes.length > LINEUP_NUM || heroes.length <= 0) {
            return resResult(STATUS.WRONG_PARMS);
        }
        if(checkPvpSeasonIsSummit()) {
            return resResult(STATUS.PVP_CAN_NOT_SAVE_DEFENSE);
        }

        let pvpDefense = await PvpDefenseModel.findByRoleId(roleId);
        if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);
        // 刷新次数
        let seasonNum: number = this.app.get('pvpSeasonNum');
        let seasonEndTime: number = this.app.get('pvpSeasonEndTime');
        let refChallengeObj = await refChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime, roleId, session.get('vipStartTime'));
        // 更新防守阵容
        let scores: number[] = [], heroIdMap = new Map<number, string>(), hids: number[] = [];
        for(let { actorId } of heroes) {
            if(isHeroHidden(actorId)) return resResult(STATUS.HERO_IS_HIDDEN);

            let heroScore = pvpDefense.heroScores.find(cur => cur.hid == actorId);
            if(heroScore) {
                scores.push(heroScore.score);
            }
            // 记录hero的objectId，用于存defense.heroes.hero
            if(pvpDefense.defense && pvpDefense.defense.heroes) {
                let heroInDefense = pvpDefense.defense.heroes.find(cur => cur.actorId == actorId);
                if(heroInDefense) {
                    heroIdMap.set(actorId, <string>heroInDefense.hero);
                } else {
                    hids.push(actorId);
                }
            } else {
                hids.push(actorId);
            }
        }
        let dbHeroes = await HeroModel.findByHidRange(hids, roleId, '_id hid ce', true);
        for(let hero of dbHeroes) {
            heroIdMap.set(hero.hid, hero._id);
        }

        let defenseHeroes = heroes.map(cur => {
            return new DefenseHero(cur, heroIdMap.get(cur.actorId));
        });
        let defense = new Defense(defenseHeroes, scores, warId, buff);
        let lineupCe = await generPvpLineupCe(roleId, pvpDefense.lineupCe, pvpDefense.attack?.heroes??[], defense.heroes, dbHeroes);
        await PvpSaveDataModel.createSaveData(roleId, warId, buff, defenseHeroes);
        pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { ...refChallengeObj, defense, lineupCe, hasDefense: true, seasonNum });
        // 返回
        let result = new PvpDataReturn();
        result.setPvpDefense(pvpDefense);
        
        return resResult(STATUS.SUCCESS, {...pick(result, ['defense', 'challengeCnt', 'challengeRefTime']), hasSaveDefense: true});
    }

    
    //8. 排行榜
    async getRank(msg: {}, session: BackendSession) {

        let roleId = session.get('roleId');

        let seasonNum: number = this.app.get('pvpSeasonNum');
        if(checkPvpSeasonIsWaiting()) { // 休赛期
            seasonNum ++;
        }

        let serverNames = await getAllServerName();
        let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum });
        r.setGenerFieldsFun(function (param: RoleRankInfo) {
            let { serverId } = param;
            return { ...param, serverName: serverNames[serverId]||'无' };
        });
        let { ranks, myRank } = await r.getRankListWithMyRank({ roleId });

        if (!myRank) {
            let pvpDefense = await PvpDefenseModel.findByRoleId(roleId);

            myRank = await r.generMyRankWithRole(roleId, pvpDefense.score, getSeconds(pvpDefense.refDaily));
        }

        return resResult(STATUS.SUCCESS, { ranks, myRank });
    }

    //2.5. 获取对手详细信息（排行榜，战报，阵容查看）
    async getPlayerDetail(msg: { roleId: string }, session: BackendSession) {

        let roleId = session.get('roleId');
        let serverId = session.get('serverId');

        let { roleId: oppoRoleId } = msg;
        let isRobot = checkRoleIsRobot(oppoRoleId);

        let result: PlayerDetail;

        if (isRobot) { // 如果是机器人，从自己的pvpDefense中寻找
            let pvpHistoryOpp = await PvpHistoryOppModel.findByRoleIdAndOppId(roleId, oppoRoleId);
            if (!pvpHistoryOpp) {
                return resResult(STATUS.PVP_ROLE_NOT_FOUND);
            }

            let heroes = new Array<PlayerDetailHero>();
            for (let hero of pvpHistoryOpp.heroes) {
                let newHero = new PlayerDetailHero();
                newHero.setPvpHeroInfo(hero);
                newHero.setIsDefense(true);
                heroes.push(newHero);
            }
            for (let hero of pvpHistoryOpp.otherHeroes) {
                let newHero = new PlayerDetailHero();
                newHero.setPvpHeroInfo(hero);
                newHero.setIsDefense(false);
                heroes.push(newHero);
            }
            result = new PlayerDetail(pvpHistoryOpp.oppRoleId, heroes, pvpHistoryOpp.rankLv);
            result.setRobot(pvpHistoryOpp);
            if(pvpHistoryOpp.isRobot) {
                result.setServerName(await getServerName(serverId));
            } else {
                let role = await RoleModel.findByRoleId(robotIdComBack(oppoRoleId), 'serverId');
                result.setServerName(await getServerName(role.serverId));
            }
        } else { // 查询对方pvpDefense
            let pvpDefense = await PvpDefenseModel.findByRoleId(oppoRoleId);
            let dbHeroes = await HeroModel.findByRole(oppoRoleId);
            let role = await RoleModel.findByRoleId(oppoRoleId);

            let heroes = new Array<PlayerDetailHero>();
            for (let dbHero of dbHeroes) {
                let hero = new PlayerDetailHero();
                hero.setByDbHero(dbHero);
                hero.setPvpDefense(pvpDefense);
                heroes.push(hero);
            }
            heroes.sort((a, b) => b.score - a.score);
            let seasonNum: number = this.app.get('pvpSeasonNum');
            let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum });
            let rank = await r.getMyRank({ roleId: oppoRoleId });//去redis中获取排名

            result = new PlayerDetail(oppoRoleId, heroes, rank);
            result.setPlayer(role);
            result.setPvpDefense(pvpDefense);
            result.setServerName(await getServerName(role.serverId));
        }

        return resResult(STATUS.SUCCESS, result);
    }

    //7. 领取巅峰之路奖励
    async receiveBox(msg: { id: number }, session: BackendSession) {
        let { id } = msg;
        let roleId = session.get('roleId');
        let sid: string = session.get('sid');
        let serverId = session.get('serverId');
        let roleName = session.get('roleName');
        
        let seasonNum: number = this.app.get('pvpSeasonNum');
        let seasonEndTime: number = this.app.get('pvpSeasonEndTime');
        let { seasonWinNum, receivedBox, challengeCnt: lastChallengeCnt, challengeRefTime: lastChallengeRefTime } = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
        let dicPvpBox = getPvpBoxBySeasonNumAndIndex(seasonNum, id);
        if(!dicPvpBox) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        if (seasonWinNum < dicPvpBox.winTimes) {
            return resResult(STATUS.PVP_NOT_REACH_BOX_SCORE);
        }
        if (receivedBox.indexOf(id) != -1) {
            return resResult(STATUS.PVP_BOX_IS_GOT);
        }
        receivedBox.push(id);
        let { challengeCnt, challengeRefTime } = await refChallengeCnt(lastChallengeCnt, lastChallengeRefTime, seasonEndTime, roleId, session.get('vipStartTime'));
        await PvpDefenseModel.updateInfo(roleId, { receivedBox, challengeCnt, challengeRefTime });
        let result = await addItems(roleId, roleName, sid, dicPvpBox.reward, ITEM_CHANGE_REASON.PVP_BOX_REWARD);
        // 任务
        await checkTask(serverId, roleId, sid, TASK_TYPE.PVP_RECEIVE_BOX);
        return resResult(STATUS.SUCCESS, { goods: result, receivedBox, challengeCnt, challengeRefTime, seasonWinNum });
    }

    //9. 战报
    async getRec(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let pvpRecords = await PvpRecordModel.getRecByRoleId(roleId);
        let serverNames = await getAllServerName();
        for(let record of pvpRecords) {
            // console.log('#####', record.defenseInfo.serverId, serverNames, serverNames[record.defenseInfo.serverId])
            if(record.defenseInfo) record.defenseInfo['serverName'] = serverNames[record.defenseInfo.serverId];
            if(record.attackInfo) record.attackInfo['serverName'] = serverNames[record.attackInfo.serverId];
        }

        return resResult(STATUS.SUCCESS, {
            list: pvpRecords.map(rec => {
                const { roleId1, battleCode, hasRpl } = rec;
                const rplFileUrl = battleCode && hasRpl ? getRemoteRplFilePath(roleId1, WAR_TYPE.PVP, battleCode) : '';
                return { ...rec, rplFileUrl };
            }),
            rplPrefixUrl: getRemoteRplPrefix(pinus.app.get('env'))
        });
    }

    // debug接口


    async addRoleScore(msg: { heroScores: Array<{ hid: number, score: number }> }, session: BackendSession) {
        let { heroScores: addHeroScores } = msg;
        let roleId = session.get('roleId');
        let sid = session.get('sid');
        let serverId = session.get('serverId');
        
        let { heroScores, hisScore, attack, defense } = await PvpDefenseModel.findByRoleId(roleId);
        let score = 0;
        for (let { hid, score: heroScore } of addHeroScores) {
            if (heroScore < 0) continue;
            let index = findIndex(heroScores, { hid });
            if (index != -1) {
                heroScores[index].score = heroScore;
            } else {
                heroScores.push({ hid, score: heroScore });
            }
        }
        for (let heroScore of heroScores) {
            score += heroScore.score;
        }
        if (score < 0) {
            score = 0;
        }
        if (hisScore < score) {
            hisScore = score;
        }

        let newAttack = <Attack>calLineupScore(attack, heroScores);
        let newDefense = <Defense>calLineupScore(defense, heroScores);

        let pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { score, hisScore, heroScores, attack: newAttack, defense: newDefense });
        const role = await RoleModel.findByRoleId(roleId);

        // 加入排行榜
        let seasonNum: number = this.app.get('pvpSeasonNum');
        let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum });
        await r.setRankWithRoleInfo(roleId, pvpDefense.score, pvpDefense.updatedAt.getTime(), role);

        // 任务
        await checkTask(serverId, roleId, sid, TASK_TYPE.PVP_HERO_SCORE, { heroScores });

        return resResult(STATUS.SUCCESS, { score, hisScore, heroScores });
    }

    async debugPvpSeasonResetTime(msg: {}, session: BackendSession) {
        return resResult(STATUS.DEBUG_FUNCTION_ERR);
    }

    async debugAddChallengeCnt(msg: { challengeCnt: number }, session: BackendSession) {
        let { challengeCnt } = msg;
        let roleId = session.get('roleId');
        if (challengeCnt > PVP.PVP_CHALLENGE_COUNTS) {
            challengeCnt = PVP.PVP_CHALLENGE_COUNTS;
        }
        let { challengeRefTime } = await PvpDefenseModel.updateInfoAndInclude(roleId, { challengeCnt, challengeRefTime: nowSeconds(), refOppCnt: 0 });
        return resResult(STATUS.SUCCESS, { challengeCnt, challengeRefTime });
    }

    async debugResetRefOppCnt(msg: { magicWord: string }, session: BackendSession) {
        const { magicWord } = msg;
        if (magicWord !== DEBUG_MAGIC_WORD) {
            return resResult(STATUS.TOKEN_ERR);
        }
        let roleId = session.get('roleId');
        await PvpDefenseModel.updateInfo(roleId, { refOppCnt: 0 });
        return resResult(STATUS.SUCCESS);
    }

    async debugResetAttackCnt(msg: { magicWord: string }, session: BackendSession) {
        const { magicWord } = msg;
        if (magicWord !== DEBUG_MAGIC_WORD) {
            return resResult(STATUS.TOKEN_ERR);
        }
        let roleId = session.get('roleId');
        await PvpDefenseModel.updateInfo(roleId, { setAttackCnt: 0, buyAttackCnt: 0 });
        return resResult(STATUS.SUCCESS);
    }

    async debugResetBox(msg: { magicWord: string }, session: BackendSession) {
        const { magicWord } = msg;
        if (magicWord !== DEBUG_MAGIC_WORD) {
            return resResult(STATUS.TOKEN_ERR);
        }
        let roleId = session.get('roleId');
        await PvpDefenseModel.updateInfo(roleId, { hisScore: 5000, receivedBox: [] });
        return resResult(STATUS.SUCCESS);
    }
}
