
import { PvpDefenseModel, PvpDefenseType, pvpUpdateInter } from '../db/PvpDefense';
import { Defense, Attack, LineupCe, OppPlayer, HeroScore, HeroReward, OppPlayerReturn, AttackHero, DefenseHero } from '../domain/battleField/pvp';
import { RoleType, CeAttrDataRole } from '../db/Role';
import { PVP_HERO_POS, REDIS_KEY, PVP_CONST, COUNTER, TASK_TYPE, MAIL_TYPE, TA_EVENT } from '../consts';
import { dicPvpOpponent, DicPvpOpponent } from "../pubUtils/dictionary/DicPvpOpponent";
import { getRandSingleIndex, genCode, shouldRefresh, getChineseName, makeRobotId, robotIdComBack, getRandSingleEelm } from '../pubUtils/util';
import { pvpEndParamInter, RewardInter } from '../pubUtils/interface';
import { gameData, getPLvByScore, getPvpHeroRewardsByScore, getPvpRankRewardsByRank, getPvpDifficultByScore } from "../pubUtils/data";
import { PVP } from '../pubUtils/dicParam';
import { PVPConfigModel, PVPConfigType } from '../db/SystemConfig'
import { nowSeconds, getTimeFun } from '../pubUtils/timeUtil';
import { HeroesRecord, PvpRecordPlayerInfo } from '../db/PvpRecord';
import { HeroModel, CeAttrData, HeroType } from '../db/Hero';
import { AttributeCal } from '../domain/roleField/attribute';
import { PvpEnemies, PvpHeroInfo, PvpOtherHeroes } from '../domain/dbGeneral';
import { DicWarJson } from '../pubUtils/dictionary/DicWarJson';
import { findWhere, findIndex } from 'underscore';
import { pinus } from 'pinus';
import { PvpHistoryOppModel, PvpHistoryOppType } from '../db/PvpHistoryOpp';
import { Rank } from './rankService';
import { CounterModel } from '../db/Counter';
import { DicRankRewads } from '../pubUtils/dictionary/DicPvpRankReward';
import { PvpSeasonResultModel, PvpSeasonResultType } from '../db/PvpSeasonResult';
import { checkTask } from '../services/taskService';
import { sendMailByContent } from './mailService';
import { RoleRankInfo } from '../domain/rank';
import { reportTAEvent } from './sdkService';

/**
 * 返回对手三人信息
 * 
 * @param oppPlayers pvpDefense表中的oppPlayers字段，需要populate过的
 * @param pLv 玩家本人的队伍等级
 */
export async function getEnemies(oppPlayers: OppPlayer[], winStreakNum: number) {

    let result = new Array<OppPlayerReturn>();
    for (let oppPlayer of oppPlayers) {
        let dicOpponent = dicPvpOpponent.get(oppPlayer.pos);
        let oppDef = <PvpHistoryOppType>oppPlayer.oppDef; // select 'oppRoleId pos roleName head frame spine rankLv pLv defCe'

        if (oppDef) delete oppDef.heroes;
        result.push({
            ...oppDef,
            roleId: oppDef.oppRoleId,
            defCe: oppDef.defCe,
            addScore: dicOpponent.score,
            rankLv: oppDef.rankLv,
            plusScore: getPlusScore(winStreakNum)
        });
    }
    return result
}

/**
 * @description 刷新对手三个人
 * @param role 数据库里我的role
 * @param score 我的军功
 * @param pLv 我的排名
 */
export async function refreshEnemies(role: RoleType, seasonNum: number, sumScore: number, score: number, pLv: number) {
    let { roleId } = role;
    let oppPlayers: OppPlayer[] = [];
    let opp = dicPvpOpponent.values()
    for (let dicOpp of opp) {
        let flag = false; // 是否筛选成功
        if (sumScore >= PVP_CONST.SCORE_LINE) { // 将这个放到const
            flag = await matchPlayer(seasonNum, oppPlayers, roleId, pLv, dicOpp); // 按照等级匹配对手
            if (!flag) flag = await matchPlayerByRank(seasonNum, oppPlayers, roleId, dicOpp.id); // 当前后分数段没有时，返回前一名的玩家
            if (!flag) flag = await matchRobot(oppPlayers, role, score, dicOpp);
        } else {
            flag = await matchRobot(oppPlayers, role, score, dicOpp);
        }
        if (!flag) continue;
    }

    return oppPlayers;
}

export async function matchPlayerByRank(seasonNum: number, oppPlayers: OppPlayer[], roleId: string, pos: number) {
    // console.log('matchPlayerByRank', JSON.stringify(oppPlayers))
    let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum });
    let ridRanks = new Array<number>(); // 已经被使用了的排名
    for (let { roleId: curRoleId } of oppPlayers) {
        let rankLv = await r.getMyRank({ roleId: robotIdComBack(curRoleId) });
        ridRanks.push(rankLv);
    }

    let myRank = await r.getMyRank({ roleId });
    ridRanks.push(myRank);

    let oppRoleId = '';
    let oppRank = 0;
    if (myRank == 0) {
        return false
    } else if (myRank == 1) { // 第一名
        if (pos == 1) {
            oppRank = 2;
            while (ridRanks.includes(oppRank)) {
                oppRank--;
            }
        } else if (pos == 2) {
            oppRank = 3;
            while (ridRanks.includes(oppRank)) {
                oppRank--;
            }
        } else {
            oppRank = 4;
            while (ridRanks.includes(oppRank)) {
                oppRank++;
            }
        }
    } else if (myRank == 0) {
        return false
    } else {
        if (pos == 1 || pos == 2) { // 刷新我前一名
            oppRank = myRank - 1;
            while (ridRanks.includes(oppRank)) {
                oppRank--;
            }
        } else { // 刷新我后一名
            oppRank = myRank + 1;
            while (ridRanks.includes(oppRank)) {
                oppRank++;
            }
        }
    }
    let result = await r.getUserByRank(oppRank);
    if (result.length <= 0) return false;
    oppRoleId = result[0];

    let pvpdefense = await PvpDefenseModel.findByRoleIdIncludeAll(oppRoleId);
    if (!pvpdefense || pvpdefense.seasonNum != seasonNum) return false;
    let pvpHistoryOpp = await generPlayerOppHis(pvpdefense, roleId, pos);
    if (!pvpHistoryOpp) return false;

    oppPlayers.push({
        roleId: pvpHistoryOpp.oppRoleId,
        oppDef: pvpHistoryOpp._id,
        pos,
        isRobot: false,
    });
    return true
}

async function matchPlayer(seasonNum: number, oppPlayers: OppPlayer[], roleId: string, pLv: number, dicOpp: DicPvpOpponent) {
    // console.log('matchPlayer', JSON.stringify(oppPlayers))

    let { id: pos, minLv, maxLv } = dicOpp
    let range = await PvpDefenseModel.findByTeamLv(seasonNum, pLv + minLv, pLv + maxLv);
    range = range.filter(cur => {
        return oppPlayers.findIndex(ccur => ccur.roleId == makeRobotId(cur.roleId)) == -1;
    });
    if (range.length <= 0) return false;

    let index = getRandSingleIndex(range.length);
    let result = range[index]; // 本次匹配结果 pvpdefense
    if (!result) return false;
    if (result.roleId == roleId) {
        range.splice(index, 1);
        if (range.length <= 0) return false;
        index = getRandSingleIndex(range.length);
        result = range[index];
    }
    let pvpHistoryOpp = await generPlayerOppHis(result, roleId, pos);
    if (!pvpHistoryOpp) return false;
    oppPlayers.push({
        roleId: pvpHistoryOpp.oppRoleId,
        oppDef: pvpHistoryOpp._id,
        pos,
        isRobot: false,
    });
    return true;
}

/**
 * @description 对手是玩家时，生成并返回pvpHistoryOpp
 * @param result 随机出的对手pvpDefense
 * @param roleId 自己的玩家id
 * @param pos 刷新这个对手的位置
 */
async function generPlayerOppHis(pvpdefense: PvpDefenseType, roleId: string, pos: number) {
    let { heroScores, defense } = pvpdefense;
    if(!defense) return false;
    let { warId, heroes: defenseHeroes } = defense;
    let role = <RoleType>pvpdefense.role;

    let seasonNum: number = pinus.app.get('pvpSeasonNum');
    let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum });
    let rankLv = await r.getMyRank({ roleId: role.roleId });
    let dbHeroes = await HeroModel.findByRole(role.roleId, [{ field: 'ce', sortBy: -1 }]);
    let heroes = new Array<PvpEnemies>();
    let otherHeroes = new Array<PvpOtherHeroes>(); // 阵容外的所有武将信息
    let defCe = 0;
    for (let dbHero of dbHeroes) {
        let h = defenseHeroes.find(cur => cur.actorId == dbHero.hid); // 阵容里是否有这个武将
        let hs = heroScores.find(cur => cur.hid == dbHero.hid); // 这个武将是否有这个得分
        if (!!h) {
            let mapWarJson = gameData.warJson.get(warId);
            let warJson = mapWarJson.find(cur => cur.dataId == h.dataId);
            if (warJson && warJson.relation == 2) {
                let heroInfo = new PvpHeroInfo();
                heroInfo.setHeroInfo(dbHero);
                // heroInfo.setOutIndex(h.order);
                let { attribute, ce } = getPlayerAttribute(dbHero.lv, dbHero.attr, role.attr);
                heroInfo.setAttribute(attribute);
                let enemy = new PvpEnemies(warJson, heroInfo, hs ? hs.score : 0, ce);
                enemy.setOutIndex(h.order);
                heroes.push(enemy);
                defCe += ce;
            }
        } else {
            let heroInfo = new PvpOtherHeroes(hs ? hs.score : 0);
            heroInfo.setHeroInfo(dbHero);
            otherHeroes.push(heroInfo);
        }
    }
    heroes.sort((a, b) => b.score - a.score);
    otherHeroes.sort((a, b) => b.score - a.score);

    let pvpHistoryOpp = await PvpHistoryOppModel.createPvpOpp({
        ...defense, defCe, ...role, pos, rankLv, heroes, otherHeroes, roleId, oppRoleId: makeRobotId(pvpdefense.roleId)
    });
    return pvpHistoryOpp;
}

async function matchRobot(oppPlayers: OppPlayer[], role: RoleType, score: number, dicOpp: DicPvpOpponent) {
    // console.log('matchRobot', JSON.stringify(oppPlayers))

    let { lv: myLv, roleId } = role;
    let { id: pos, minLv, maxLv, ratio } = dicOpp;

    let result = getRandSingleEelm(gameData.pvpWar);
    if (!result) return false;

    let robotWarjson = gameData.warJson.get(result.war_id);
    if (!robotWarjson) return false
    let heroes: PvpEnemies[] = [];
    let defCe = 0;
    for (let h of robotWarjson) {
        if (h.relation == 1) continue;
        let actorId = h.randomEnemy.length > 0? getRandSingleEelm(h.randomEnemy): 0;
        let dicHero = gameData.hero.get(actorId);
        if (!dicHero) continue;
        let heroInfo = new PvpHeroInfo();
        let { attribute, ce, lv } = getRobotAttribute(actorId, ratio, score);
        heroInfo.setRobotInfo(dicHero, lv);
        defCe += ce;
        heroInfo.setAttribute(attribute);
        let enemy = new PvpEnemies(h, heroInfo, 0, ce);
        enemy.setOutIndex(h.outIndex);
        heroes.push(enemy);
    }

    let oppRoleId = generateRobotRoleId();
    let roleName = getChineseName();
    let pLv = getPLvByScore(score);
    let hisPLv = Math.floor(pLv + (minLv + maxLv) / 2);
    if (hisPLv < 1) hisPLv = 1

    let pvpHistoryOpp = await PvpHistoryOppModel.createPvpOpp({
        roleId, oppRoleId, roleName, pos, defCe, pLv: hisPLv, lv: myLv, heroes, rankLv: 0, warId: result.war_id, buff: getRandSingleEelm(result.mapseid)||0,
    });

    oppPlayers.push({
        roleId: oppRoleId,
        oppDef: pvpHistoryOpp._id,
        pos,
        isRobot: true
    });
    return true
}

// 生成机器人roleId
function generateRobotRoleId() {
    return `${genCode(10)}_r`;
}

// 根据连胜次数，获得加成的积分
export function getPlusScore(win: number) {
    let result = win - 1;
    if (result < 0) result = 0;
    if (result > PVP.PVP_WINREWARD_UPLIMIT) result = PVP.PVP_WINREWARD_UPLIMIT;
    return result;
}

export function getLvByScore(heroScores: HeroScore[]) {
    heroScores.sort((a, b) => b.score - a.score);
    let score = 0;
    for (let i = 0; i < 5; i++) {
        if (!heroScores[i]) break;
        score += heroScores[i].score;
    }
    return getPLvByScore(score);
}

export function refChallengeCnt(challengeCnt: number, challengeRefTime: number, seasonEndTime: number) {
    let hasChanged = false;
    if (challengeCnt >= PVP.PVP_CHALLENGE_COUNTS) {
        return { hasChanged, challengeCnt, challengeRefTime: nowSeconds() };
    }
    let period = PVP.PVP_CHALLENGE_NORMALTIMES * 60;
    if (getTimeFun(seasonEndTime).checkDay()) {
        period = PVP.PVP_CHALLENGE_FINALTIMES * 60;
    }
    let time = nowSeconds();
    let num = Math.floor((time - challengeRefTime) / period);
    if (num > 0) {
        challengeCnt += num;
        challengeRefTime = challengeRefTime + period * num;
        hasChanged = true;
    }
    challengeCnt = challengeCnt > PVP.PVP_CHALLENGE_COUNTS ? PVP.PVP_CHALLENGE_COUNTS : challengeCnt;
    return { hasChanged, challengeCnt, challengeRefTime };
}

export function comsumeChallengeCnt(challengeCnt: number, challengeRefTime: number, seasonEndTime: number) {
    challengeCnt--;
    if (challengeCnt >= PVP.PVP_CHALLENGE_COUNTS) {
        return { challengeCnt, challengeRefTime };
    }
    if (challengeCnt == PVP.PVP_CHALLENGE_COUNTS - 1) {
        challengeRefTime = nowSeconds();
        return { challengeCnt, challengeRefTime };
    }
    return refChallengeCnt(challengeCnt, challengeRefTime, seasonEndTime);
}

export async function sendLastSeasonRewardIfNotSent(pvpDefense: PvpDefenseType) {
    let seasonNum: number = pinus.app.get('pvpSeasonNum');
    if(pvpDefense.seasonNum < seasonNum) {
        let oldPvpCongig = await PVPConfigModel.findPVPConfig(pvpDefense.seasonNum);
        let result = await sendPVPRewardToUser(pvpDefense, pvpDefense.seasonNum, oldPvpCongig.seasonEndTime);
        pvpDefense = result.pvpDefense;
    }
    return pvpDefense;
}

// 获取刷新对手次数及消耗
export function refreshRefOppCnt(pvpDefense: PvpDefenseType) {
    let { refOppCnt = 0, setAttackCnt = 0, buyAttackCnt = 0, refDaily } = pvpDefense;
    let curTime = new Date();
    let shouldRefOpp = shouldRefresh(refDaily, curTime);
    if (shouldRefOpp) {
        refOppCnt = 0; setAttackCnt = 0; buyAttackCnt =0; refDaily = curTime;
    }
    return {
        shouldRefOpp,
        refOppCnt, refDaily, setAttackCnt, buyAttackCnt,
        consume: gameData.pvpRefreshConsume.get(refOppCnt + 1)
    }
}


/**
 * 根据比例计算机器人属性
 * @param attribute 出兵表中的属性字段
 * @param ce 我的战力
 * @param enemyCe 出兵表对手战力
 * @param ratio 系数
 */
export function getRobotAttribute(hid: number, posRatio: number, score: number) {

    let difficultRatio = getPvpDifficultByScore(score);
    let dicHero = gameData.hero.get(hid);

    let newAttribute = new AttributeCal();
    newAttribute.setLv(difficultRatio.enemyLv);
    newAttribute.setByMap(dicHero.baseAbilityArr, difficultRatio.value / 10000 * posRatio);
    let attrArr = newAttribute.getReduceAttributesToString();
    let newCe = newAttribute.calCelAndReduce();
    return { attribute: attrArr, ce: newCe, lv: difficultRatio.enemyLv };
}

/**
 * @description 根据玩家数据获取到他的属性
 * @param ceAttr hero表的ceAttr
 * @param globalCeAttr role表中的globalCeAttr
 */
export function getPlayerAttribute(lv: number, heroAttrs: CeAttrData[] = [], roleAttrs: CeAttrDataRole[] = []) {
    let newAttribute = new AttributeCal();
    newAttribute.setLv(lv);
    newAttribute.setByDbData(roleAttrs, heroAttrs);
    let attribute = newAttribute.getReduceAttributesToString();
    let ce = newAttribute.calCelAndReduce();
    return { attribute, ce };
}

/**
 * @description 根据玩家数据获取到他的主属性
 * @param ceAttr 
 * @param globalCeAttr 
 */
export function getPlayerMainAttribute(heroAttrs: CeAttrData[], roleAttrs: CeAttrDataRole[]) {
    let newAttribute = new AttributeCal();
    newAttribute.setByDbData(roleAttrs, heroAttrs);
    let mainAttributes = newAttribute.getReduceAttributes();
    return mainAttributes;
}

// 获取我方战报记录
export async function generMyRecInfo(pvpDefense: PvpDefenseType, role: RoleType, isSuccess: boolean, pos: number, myHeroes: pvpEndParamInter[]) {
    let { attack, defense, heroScores, winStreakNum, hisWinStreakNum = 0, score, hisScore } = pvpDefense;
    let { roleId } = role;
    if (isSuccess) {
        winStreakNum ++;
    } else {
        winStreakNum = 0;
    }
    if(winStreakNum > hisWinStreakNum) {
        hisWinStreakNum = winStreakNum;
    }

    const dicOpp = gameData.pvpOpponent.get(pos);
    const plusScore = getPlusScore(winStreakNum);
    let pLv = getLvByScore(heroScores);

    let myHeroRecords: HeroesRecord[] = []; // 存入rec里面的数据
    let showHeroScores = new Array<{ hid: number, addScore: number, plusScore: number, score: number }>();
    let addSumScore = 0;
    for (let { actorId: hid } of attack.heroes) {
        if(hid == 0) continue;
        let params = myHeroes.find(cur => cur.hid == hid);
        let curHeroScore = heroScores.find(cur => cur.hid == hid);
        if (isSuccess) {
            if (!curHeroScore) {
                curHeroScore = {
                    hid, score: dicOpp.score + plusScore
                };
                heroScores.push(curHeroScore);
            } else {
                curHeroScore.score += dicOpp.score + plusScore;
            }
            addSumScore += dicOpp.score + plusScore;
            showHeroScores.push({
                hid, addScore: dicOpp.score, plusScore, score: curHeroScore.score
            });
        } else {
            showHeroScores.push({
                hid, addScore: 0, plusScore: 0, score: curHeroScore ? curHeroScore.score : 0
            });
        }
        const myHero = await HeroModel.findByHidAndRole(hid, roleId, 'quality star colorStar lv skinId');

        let record = new HeroesRecord();
        record.setByHero(myHero, params);
        myHeroRecords.push(record);
    }

    let attackInfo = new PvpRecordPlayerInfo();
    attackInfo.setByRole(role, myHeroRecords, isSuccess, isSuccess ? addSumScore : 0, pLv)

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

    let updateParam = {
        winStreakNum, hisWinStreakNum, attack: newAttack, defense: newDefense, heroScores, score: score + addSumScore, hisScore: hisScore > score + addSumScore? hisScore: score + addSumScore
    }

    return { attackInfo, showHeroScores, updateParam }
}

function calLineupScore(lineup: Attack|Defense, heroScores: HeroScore[]) {
    if(!lineup) return lineup;
    let score = 0;
    for(let { actorId } of lineup.heroes) {
        let hs = heroScores.find(cur => cur.hid == actorId);
        if(hs) {
            score += hs.score;
        }
    }
    let pLv = getPLvByScore(score);
    return {...lineup, score, pLv}
}

// 获取对手战报记录
export async function generPVPOppRecInfo(isSuccess: boolean, curOpp: OppPlayer, oppHeroes: pvpEndParamInter[], myLv: number) {
    let oppHeroRecords = new Array<HeroesRecord>();
    let oppRole = <PvpHistoryOppType>curOpp.oppDef;
    if (!oppRole) { console.error('opp role not found') }

    for (let params of oppHeroes) {
        let historyHero = oppRole.heroes.find(cur => cur.actorId == params.hid);
        if (historyHero) {
            let hs = new HeroesRecord();
            hs.setByPvpHeroInfo(historyHero, params);
            oppHeroRecords.push(hs);
        }
    }
    let addSumScore = 0;
    if(!curOpp.isRobot && !isSuccess) {
        let pvpDefense = await PvpDefenseModel.findByRoleId(oppRole.roleId);
        if(pvpDefense && pvpDefense.defense) {
            let { attack, defense, heroScores, score } = pvpDefense;
            for(let { actorId } of defense.heroes) {
                let hs = heroScores.find(cur => cur.hid == actorId);
                if(hs) {
                    hs.score += PVP.PVP_DEFENSE_SUCCESS_REWARD;
                } else {
                    heroScores.push({ hid: actorId, score: PVP.PVP_DEFENSE_SUCCESS_REWARD })
                }
                addSumScore += PVP.PVP_DEFENSE_SUCCESS_REWARD;
            }

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

            await PvpDefenseModel.updateInfo(oppRole.roleId, { attack: newAttack, defense: newDefense, heroScores, score: score + addSumScore });

        }
    }

    let defenseInfo = new PvpRecordPlayerInfo();
    defenseInfo.setByHistoryOpp(oppRole, oppHeroRecords, !isSuccess, isSuccess ? 0 : addSumScore)
    return defenseInfo
}

/**
 * pvp定时任务赛季结算
 * @param obj 
 */
 export async function pvpSeasonEnd(seasonNum: number) {
    let pvpConfig = await PVPConfigModel.findPVPConfig(seasonNum);
    if(pvpConfig.hasSettleReward) return;

    console.log('exce pvpSeasonEnd' + pvpConfig.seasonNum);
    let resultMaxRank = gameData.pvpRankMax.max;//根据排行榜的奖励表，获得最大排名挡位的最小值，其余不在结算中结算的玩家按照最大排名挡位在登录或进入pvp时结算
    let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum: pvpConfig.seasonNum }, false, resultMaxRank.min - 1);
    let allRank = <RoleRankInfo[]>(await r.getRankByRange());
    console.log('******** allRank', 0, resultMaxRank.min - 2, allRank)
    for(let { rank, roleId } of allRank) {
        console.log('******** pvpSeasonEnd: ', rank, roleId);
        let pvpDefense = await PvpDefenseModel.findByRoleId(roleId);
        let { pvpSeasonResult } = await sendPVPRewardToUser(pvpDefense, pvpConfig.seasonNum, pvpConfig.seasonEndTime);
        reportTAEvent(roleId, TA_EVENT.PVP_SEASON_END, { top_rank: rank, hero_score: pvpSeasonResult.heroScores })
    }
    await PVPConfigModel.setReward(pvpConfig.seasonNum);
}

/**
 * pvp定时任务结算获得添加邮件信息
 * @param pvpDefense 
 * @param seasonNum 
 * @param oldSeasonEndTime 
 */
export async function sendPVPRewardToUser(pvpDefense: PvpDefenseType, seasonNum: number, seasonEndTime: number, notPush?: boolean) {
    //检查并返回排名结算以及武将功勋结算
    let pvpSeasonResult = await savePvpSeasonResult(pvpDefense, seasonNum, seasonEndTime);
    let { rankGoods, heroGoods, rankLv } = pvpSeasonResult;
    //下发邮件
    if (!!rankGoods.length) //排名奖励
        await sendMailByContent(MAIL_TYPE.PVP_RANK_REWARD, pvpDefense.roleId, {
            params: [JSON.stringify(seasonNum), (rankLv > 1000 ? '999+' : JSON.stringify(rankLv))],
            goods: rankGoods, notPush
        });
    if (!!heroGoods.length) //武将功勋奖励
        await sendMailByContent(MAIL_TYPE.PVP_RESULT, pvpDefense.roleId, {
            params: [JSON.stringify(seasonNum)],
            goods: heroGoods,  notPush
        });

    return {
        pvpSeasonResult,
        pvpDefense: await resetPvpScores(pvpDefense, seasonNum + 1, pvpSeasonResult)
    }
}

async function resetPvpScores(pvpDefense: PvpDefenseType, seasonNum: number, pvpSeasonResult: PvpSeasonResultType) {
    let { roleId, attack, defense } = pvpDefense;
    let { newHeroScores, newScore } = pvpSeasonResult;

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

    pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { 
        heroScores: newHeroScores, score: newScore, attack: newAttack, defense: newDefense,
        seasonNum, challengeCnt: PVP.PVP_CHALLENGE_COUNTS, challengeRefTime: 0, winStreakNum: 0, isFirstEntry: true
    });
    return pvpDefense;
}

/**
 * 检查并返回排名结算以及武将功勋结算
 * @param pvpDefense 
 * @param seasonNum 
 * @param oldSeasonEndTime 
 * @param rankLv 
 */
export async function savePvpSeasonResult(pvpDefense: PvpDefenseType, seasonNum: number, seasonEndTime: number, rankLv?: number) {
    if (!rankLv) {
        let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum });
        rankLv = await r.getMyRank({ roleId: pvpDefense.roleId });// 获得排行榜排名
    }
    let pvpRankReward: DicRankRewads = getPvpRankRewardsByRank(rankLv);
    let rankGoods: RewardInter[] = [];
    if (pvpRankReward) {
        rankGoods = pvpRankReward.reward;//排名奖励
    }
    let heroGoods: HeroReward[]  = [];
    let newHeroScores: HeroScore[] = [], newScore = 0;
    for (let heroScore of pvpDefense.heroScores) {
        let pvpHeroReward = getPvpHeroRewardsByScore(heroScore.score); //获得武将功勋奖励
        if (pvpHeroReward) {
            newHeroScores.push({...heroScore, score: pvpHeroReward.heroscore });
            for(let { id, count } of pvpHeroReward.reward) {
                heroGoods.push({
                    hid: heroScore.hid, id, count
                });
            }
            newScore += pvpHeroReward.heroscore;
        } else {
            newHeroScores.push(heroScore);
            newScore += heroScore.score;
        }
    }

    //pvp锁定的信息存入赛季结算表中
    let pvpSeasonResult = await PvpSeasonResultModel.updatePvpSeasonResult(pvpDefense.roleId, seasonNum, {
        ...pvpDefense, rankLv, heroGoods, rankGoods, show: true, newScore, newHeroScores, seasonEndTime
    });//结算修改玩家pvp信息
    if(newScore > 0) {
        let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum: seasonNum + 1 });
        await r.setRankWithRoleInfo(pvpDefense.roleId, newScore, Date.now());
    }

    // 更新任务
    await checkTask(pvpDefense.roleId, null, TASK_TYPE.PVP_HERO_SCORE, 0, false, { heroScores: pvpDefense.heroScores });
    await checkTask(pvpDefense.roleId, null, TASK_TYPE.PVP_RANK, 1, false, { rankLv });
    return pvpSeasonResult;
}

export async function generPvpLineupCe(roleId: string, lineupCe: LineupCe[], newHeroes: AttackHero[]|DefenseHero[], dbHeroes: HeroType[]) {
    let newHids: number[] = []; // 本次新增武将
    let newLineupCe: { hid: number, ce: number }[] = []; // 新生成的lineupCe字段
    for(let { actorId } of newHeroes) {
        let n = newLineupCe.find(cur => cur.hid == actorId);
        if(!n) {
            let lineup = lineupCe.find(cur => cur.hid == actorId);
            if(lineup) {
                newLineupCe.push(lineup);
            } else {
                let dbHero = dbHeroes.find(cur => cur.hid == actorId);
                if(dbHero) {
                    newLineupCe.push({ hid: actorId, ce: dbHero.ce });
                } else {
                    newHids.push(actorId);
                }
            }
        }
    }
    let heroes = await HeroModel.findByHidRange(newHids, roleId, 'hid ce', true);
    for(let { hid, ce } of heroes) {
        newLineupCe.push({ hid, ce });
    }
    return newLineupCe;
}