import { Application, BackendSession, ChannelService, HandlerService, pinus } from "pinus";
import { GVG_ITEM, DATA_NAME, GVG_ACTIVE_TYPE, GVG_PERIOD, GVG_SERVER_TYPE, ITEM_CHANGE_REASON, LEAGUE_JOB, LEAGUE_MANAGE_TYPE, STATUS, GVG_REC_TYPE, TASK_TYPE, GVG_TECH_TYPE, PUSH_ROUTE } from "../../../consts";
import { GVGLeagueModel } from "../../../db/GVGLeague";
import { GVGLeaguePrepareModel } from "../../../db/GVGLeaguePrepare";
import { GuardCityInfoPage, GVGMainData, LeagueContributeInfo, LeagueMemberContributeInfo, LeagueRankInInfoPage } from "../../../domain/gvgField/returnData";
import { getRandEelm, resResult } from "../../../pubUtils/util";
import { calLeagueCe, getGroupIdOfServer, getGroupKey, getGVGConfig, getGVGPeriodData, getGVGServerType, getServerTypeByTime } from "../../../services/gvg/gvgService";
import { autoCreateLeague, checkCanChooseJob, checkCanPrepare, checkLeagueAuth, getMyAuth } from "../../../services/gvg/gvgTeamService";
import { getAllServerName } from "../../../services/redisService";
import { Contribute, GVGUserDataModel } from "../../../db/GVGUserData";
import { GVGUserItemModel } from "../../../db/GVGUserItem";
import { GVGUserTaskModel } from "../../../db/GVGUserTask";
import { GVG } from "../../../pubUtils/dicParam";
import { RoleModel } from "../../../db/Role";
import { addGVGTechActive, calFighterContribute, calProducerContribute, checkPreTech, checkTechIsIng, getDailyLoginReward, getMyContribute, pushTechChange } from "../../../services/gvg/gvgPrepareService";
import { GVGUserDailyDataModel } from "../../../db/GVGUserDailyData";
import { gameData } from "../../../pubUtils/data";
import { lockLeagueData } from "../../../services/redLockService";
import { addGVGReward, handleGVGCost } from "../../../services/gvg/gvgItemService";
import { RewardInter } from "../../../pubUtils/interface";
import { getGVGCities, getGVGCitiesInfo } from "../../../services/gvg/gvgBattleService";
import { GVGRecModel } from "../../../db/GVGRec";
import { checkGVGTask } from "../../../services/task/taskService";
import { getFightTimeByPeriod, getMyVestiges, getVestiges } from "../../../services/gvg/gvgFightService";
import { getSeconds } from "../../../pubUtils/timeUtil";
import { GVGVestigeRankModel } from "../../../db/GVGVestigeRank";
import { addTechActivateMessage, addTechUnlockMessage } from "../../../services/gvg/gvgRecService";
import { GuildModel } from "../../../db/Guild";
import { GVGCityModel } from "../../../db/GVGCity";

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

export class GVGHandler {
    channelService: ChannelService;
    constructor(private app: Application) {
        this.channelService = app.get('channelService');
    }

    // 测试
    async getData(msg: {}, session: BackendSession) {
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const serverId = session.get('serverId');
        const guildCode = session.get('guildCode');
        const sid = session.get('sid');

        let { configId, period, countdownTime } = getGVGPeriodData();
        let serverType = await getGVGServerType(serverId);
        if(serverType == GVG_SERVER_TYPE.NO) return resResult(STATUS.GVG_NO_SERVER_TYPE);

        let data = new GVGMainData(configId, period, countdownTime, serverType);

        let serverNames = await getAllServerName();
        let league = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!league) {
            league = await autoCreateLeague(guildCode);
        }
        if(league) {
            data.setLeague(league, serverNames);
        
            let leaguePrepare = await GVGLeaguePrepareModel.findByLeague(configId, league.leagueCode);
            data.setLeagueParpare(leaguePrepare);
            
            let userData = await GVGUserDataModel.findByRole(configId, league.leagueCode, roleId);
            let items = await GVGUserItemModel.findByRole(configId, league.leagueCode, roleId);
            let tasks = await GVGUserTaskModel.findByRole(configId, league.leagueCode, roleId);
            data.setPlayerInfo(userData, getMyAuth(league, roleId), await checkCanPrepare(roleId), checkCanChooseJob(userData?.job, leaguePrepare), items, tasks);

            let dailyReward = await getDailyLoginReward(roleId, roleName, sid, league.leagueCode, userData?.job);
            if(dailyReward) data.setFistLogin(dailyReward.reward);

            data.setLeagueCe(await calLeagueCe(league));

            let cities = await getGVGCities(league);
            data.setCities(cities);
        }

        return resResult(STATUS.SUCCESS, data)
    }

    async getMap(msg: {}, session: BackendSession) {
        const roleId = session.get('roleId');
        const serverId = session.get('serverId');
        const guildCode = session.get('guildCode');

        // if(!await checkCanPrepare(roleId)) return resResult(STATUS.GVG_CANNOT_PREPARE); // TODO 临时去拦截

        let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        let { configId, period, countdownTime } = getGVGPeriodData();
        let { startFightTime, endFightTime } = getFightTimeByPeriod(period);

        let groupKey = await getGroupKey(serverId);
        let cities = await getGVGCitiesInfo(configId, groupKey, myLeague);
        let vestiges = await getMyVestiges(serverId, roleId);

        return resResult(STATUS.SUCCESS, {
            configId, period, countdownTime, startFightTime, endFightTime,
            cities,
            vestiges
        });
    }

    // 获取动态
    async getRec(msg: {}, session: BackendSession) {
        const guildCode = session.get('guildCode');

        let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);
        
        const recs = await GVGRecModel.findByLeague(myLeague.leagueCode, GVG_REC_TYPE.PREPARE);
        return resResult(STATUS.SUCCESS, { recs });
    }

    // 选择职能
    async chooseJob(msg: { job: number }, session: BackendSession) {
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const sid = session.get('sid');
        const guildCode = session.get('guildCode');
        const { job } = msg;

        let { configId, period } = getGVGPeriodData();
        if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);

        let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        // 是否已经选过
        let myUserData = await GVGUserDataModel.findByRole(configId, myLeague.leagueCode, roleId);
        if(myUserData && myUserData.job) return resResult(STATUS.GVG_HAS_CHOOSE_JOB); 

        let leaguePrepare = await GVGLeaguePrepareModel.findByLeague(configId, myLeague.leagueCode);
        if(!leaguePrepare) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);

        // 是否超过人数
        let limit = Math.ceil(leaguePrepare.maxMemberCnt * GVG.GVG_ROLE_TOTAL_RATIO);
        let cnt = job == LEAGUE_JOB.FIGHTER? leaguePrepare.fighterCnt: leaguePrepare.producerCnt;
        if(cnt >= Math.ceil(limit * GVG.GVG_ROLE_RATIO / 2)) {
            return resResult(STATUS.SUCCESS, {
                isSuccess: false,
                leagueCode: myLeague.leagueCode,
                job: myUserData.job,
                producerCnt: leaguePrepare.producerCnt,
                fighterCnt: leaguePrepare.fighterCnt,
            });
        }

        // 更新userData
        myUserData = await GVGUserDataModel.chooseJob(configId, myLeague.leagueCode, roleId, job);
        // 更新prepare
        leaguePrepare = await GVGLeaguePrepareModel.chooseJob(configId, myLeague.leagueCode, job);
        let dailyReward = await getDailyLoginReward(roleId, roleName, sid, myLeague.leagueCode, myUserData?.job);

        return resResult(STATUS.SUCCESS, {
            isSuccess: true,
            leagueCode: myLeague.leagueCode,
            job: myUserData.job,
            producerCnt: leaguePrepare.producerCnt,
            fighterCnt: leaguePrepare.fighterCnt,
            leagueGoods: dailyReward? dailyReward.reward: []
         });
    }

    // 查看贡献
    async getContribute(msg: {}, session: BackendSession) {
        const roleId = session.get('roleId');
        const guildCode = session.get('guildCode');

        let { configId, period } = getGVGPeriodData();
        if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);

        let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        const members = myLeague.members||[];
        const roleIds = members.map(member => member.roleId);
        const roles = await RoleModel.findByRoleIds(roleIds);
        const serverNames = await getAllServerName();

        const myUserData = await GVGUserDataModel.findByRole(configId, myLeague.leagueCode, roleId);
        const { contribute = new Contribute(), box = [] } = myUserData||{};
        const userDatas = await GVGUserDataModel.findByRoles(configId, myLeague.leagueCode, roleIds);

        const result: LeagueContributeInfo[] = [];
        for(let curJob of [LEAGUE_JOB.PRODUCER, LEAGUE_JOB.FIGHTER]) {
            const memberResult: LeagueMemberContributeInfo[] = [];
            for(let member of members) {
                let role = roles.find(role => role.roleId == member.roleId);
                if(!role) continue;
                let userData = userDatas.find(userData => userData.roleId == member.roleId);
                let obj = new LeagueMemberContributeInfo(role, serverNames);
                obj.setAuth(member.auth);
                obj.setByUserData(userData);
                if(curJob == LEAGUE_JOB.PRODUCER && calProducerContribute(obj) > 0) memberResult.push(obj);
                if(curJob == LEAGUE_JOB.FIGHTER && obj.score > 0) memberResult.push(obj);
            }

            memberResult.sort((a, b) => {
                return curJob == LEAGUE_JOB.PRODUCER? calProducerContribute(b) - calProducerContribute(a): calFighterContribute(b) - calFighterContribute(a);
            });
            for(let i = 0; i < memberResult.length; i++) {
                memberResult[i].setRank(i + 1);
            }
            let sumContribute = curJob == LEAGUE_JOB.PRODUCER? calProducerContribute(contribute): calFighterContribute(contribute); 
            let boxReceived = box.filter(boxId => {
                let dicBox = gameData.gvgContributeBox.get(boxId);
                return dicBox.job == curJob;
            });
            let disObj = new LeagueContributeInfo(curJob, sumContribute, boxReceived);
            disObj.setMembers(memberResult);
            result.push(disObj)
        }

        const userDailyData = await GVGUserDailyDataModel.findByRole(configId, myLeague.leagueCode, roleId);
        const myRanks = await GVGVestigeRankModel.findAllByRole(roleId);

        return resResult(STATUS.SUCCESS, {
            myContribute: getMyContribute(userDailyData, myRanks),
            list: result
         });
    }

    // 领取宝箱
    async receiveBox(msg: { boxId: number }, session: BackendSession) {
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const sid = session.get('sid');
        const guildCode = session.get('guildCode');

        const { boxId } = msg;
        let { configId, period } = getGVGPeriodData();
        if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);

        const myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        let dicBox = gameData.gvgContributeBox.get(boxId);
        if(!dicBox) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        let myUserData = await GVGUserDataModel.findByRole(configId, myLeague.leagueCode, roleId);
        let { contribute = new Contribute(), box = [] } = myUserData||{};

        if(box.indexOf(boxId) != -1) return resResult(STATUS.GVG_BOX_HAS_RECEIVED)
        let sumContribute = dicBox.job == LEAGUE_JOB.PRODUCER? calProducerContribute(contribute): calFighterContribute(contribute); 
        if(sumContribute < dicBox.boxPoint) return resResult(STATUS.GVG_BOX_POINT_NOT_ENOUGH);

        const leagueGoods = await addGVGReward(roleId, roleName, myLeague.leagueCode, sid, dicBox.boxLeagueReward, dicBox.boxReward, ITEM_CHANGE_REASON.GVG_RECEIVE_BOX);
        myUserData = await GVGUserDataModel.receiveBox(configId, myLeague.leagueCode, roleId, boxId);

        return resResult(STATUS.SUCCESS, {
            sumContribute,
            receivedBox: myUserData.box,
            leagueGoods
         });
    }

    // 领取升级奖励
    async receiveLvReward(msg: { lv: number }, session: BackendSession) {
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const sid = session.get('sid');
        const guildCode = session.get('guildCode');

        const { lv } = msg;
        let { configId, period } = getGVGPeriodData();
        if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);

        let dicGVGLeagueLv = gameData.gvgLeagueLv.get(lv);
        if(!dicGVGLeagueLv) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        const myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);
        const leaguePrepare = await GVGLeaguePrepareModel.findByLeague(configId, myLeague.leagueCode);

        if(!leaguePrepare || leaguePrepare.lv < lv + 1) return resResult(STATUS.GVG_LV_NOT_ENOUGH);

        let myUserData = await GVGUserDataModel.findByRole(configId, myLeague.leagueCode, roleId);
        let { receivedLv } = myUserData||{};
        if(lv != 1 && receivedLv + 1 != lv) return resResult(STATUS.GVG_LV_REWARD_NOT_REACH);
        if(receivedLv >= lv) return resResult(STATUS.GVG_LV_REWARD_HAS_RECEIVED);

        const leagueGoods = await addGVGReward(roleId, roleName, myLeague.leagueCode, sid, [], dicGVGLeagueLv.reward, ITEM_CHANGE_REASON.GVG_RECEIVE_LV);
        myUserData = await GVGUserDataModel.receiveLv(configId, myLeague.leagueCode, roleId, lv);

        return resResult(STATUS.SUCCESS, {
            receivedLv: myUserData.receivedLv,
            leagueGoods
         });
    }

    // 领取任务奖励
    async receiveTask(msg: { taskId: number }, session: BackendSession) {
        const roleId: string = session.get('roleId');
        const guildCode: string = session.get('guildCode');
        const roleName: string = session.get('roleName');
        const sid: string = session.get('sid');
        const { taskId } = msg;

        let dicGVGTask = gameData.gvgTask.get(taskId);
        if(!dicGVGTask) return resResult(STATUS.DIC_DATA_NOT_FOUND);
        let { configId } = getGVGConfig();

        const myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        // 检查
        let rec = await GVGUserTaskModel.findByTaskId(configId, myLeague.leagueCode, roleId, taskId);
        if(!rec || rec.count < dicGVGTask.condition) return resResult(STATUS.GVG_TASK_NOT_ENOUGH);
        if(rec.status == 2) return resResult(STATUS.GVG_TASK_HAS_RECEIVED);

        rec = await GVGUserTaskModel.receiveTask(configId, myLeague.leagueCode, roleId, taskId);
        let leagueGoods = await addGVGReward(roleId, roleName, myLeague.leagueCode, sid, dicGVGTask.leagueReward, dicGVGTask.reward, ITEM_CHANGE_REASON.GVG_RECEIVE_TASK);

        return resResult(STATUS.SUCCESS, {
            curTask: {
                id: rec.id,
                status: rec.status
            },
            leagueGoods
        });
    }

    // 千机阁数据
    async getTech(msg: {}, session: BackendSession) {
        const roleId = session.get('roleId');
        const guildCode = session.get('guildCode');

        let { configId, period } = getGVGPeriodData();
        if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);

        const myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);
        const leaguePrepare = await GVGLeaguePrepareModel.findByLeague(configId, myLeague.leagueCode);

        return resResult(STATUS.SUCCESS, {
            activeTech: leaguePrepare?.activeTech||[],
            queue: leaguePrepare?.techQueue||[]
         });
    }

    // 千机阁解锁
    async unlockTech(msg: { techId: number }, session: BackendSession) {
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const guildCode = session.get('guildCode');
        const { techId } = msg;

        let { configId, period } = getGVGPeriodData();
        if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);

        const dicTech = gameData.gvgTech.get(techId);
        if(!dicTech) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        const myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        // 权限
        const checkAuth = await checkLeagueAuth(roleId, myLeague, LEAGUE_MANAGE_TYPE.UNLOCK_TECH);
        if(!checkAuth) return resResult(STATUS.GVG_HAS_NO_AUTH);

        // 并发锁
        let res: any = await lockLeagueData(DATA_NAME.LEAGUE_TECH, myLeague.leagueCode);//加锁
        if (!!res.err) return resResult(STATUS.REDLOCK_ERR);

        let leaguePrepare = await GVGLeaguePrepareModel.findByLeague(configId, myLeague.leagueCode);

        if(checkTechIsIng(techId, leaguePrepare?.activeTech||[], leaguePrepare?.techQueue||[])) {
            res.releaseCallback();
            return resResult(STATUS.GVG_TECH_HAS_UNLOCKED);
        }

        if(!checkPreTech(techId, leaguePrepare?.activeTech||[], leaguePrepare?.techQueue||[])) {
            res.releaseCallback();
            return resResult(STATUS.GVG_TECH_PRE_POSITION_NOT_UNLOCK);
        }

        leaguePrepare = await GVGLeaguePrepareModel.unlockTech(configId, myLeague.leagueCode, techId, dicTech.consume);
        if(!leaguePrepare) {
            res.releaseCallback();
            return resResult(STATUS.GVG_TECH_QUEUECNT_MAX);
        }

        res.releaseCallback();
        addTechUnlockMessage(roleId, roleName, myLeague, techId);

        // 推送千机阁解锁消息
        let curQueue = leaguePrepare.techQueue.find(cur => cur.id == techId);
        await pushTechChange(myLeague.guildCodes, false, techId, curQueue.progress, curQueue.maxProgress);

        return resResult(STATUS.SUCCESS, {
            queue: leaguePrepare?.techQueue||[]
         });
    }

    // 千机阁激活
    async activate(msg: { techId: number, battleFeats: number }, session: BackendSession) {
        const serverId = session.get('serverId');
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const guildCode = session.get('guildCode');
        const sid = session.get('sid');
        const { techId, battleFeats } = msg;

        let { configId, period } = getGVGPeriodData();
        if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);

        const dicTech = gameData.gvgTech.get(techId);
        if(!dicTech) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        const myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        // 权限
        const checkAuth = await checkLeagueAuth(roleId, myLeague, LEAGUE_MANAGE_TYPE.ACTIVATE_TECH);
        if(!checkAuth) return resResult(STATUS.GVG_HAS_NO_AUTH);

        let leaguePrepare = await GVGLeaguePrepareModel.findByLeague(configId, myLeague.leagueCode);
        if(!checkTechIsIng(techId, [], leaguePrepare?.techQueue||[])) {
            return resResult(STATUS.GVG_TECH_NOT_QUEUE);
        }
        if(!leaguePrepare || leaguePrepare.lv < dicTech.levelLimit) {
            return resResult(STATUS.GVG_TECH_LV_NOT_ENOUGH);
        }

        // 扣战功
        const costResult = await handleGVGCost(roleId, myLeague.leagueCode, sid, [{ id: GVG_ITEM.BATTLE_FEAT, count: battleFeats }], [], ITEM_CHANGE_REASON.GVG_ACTIVE_TECH);
        if(!costResult) return resResult(STATUS.GVG_BATTLE_FEAT_NOT_ENOUGH);

        leaguePrepare = await GVGLeaguePrepareModel.addProgress(configId, myLeague.leagueCode, techId, battleFeats);
        if(!leaguePrepare) {
            return resResult(STATUS.GVG_TECH_NOT_QUEUE);
        }
        let curQueue = leaguePrepare.techQueue.find(cur => cur.id == techId);
        if(curQueue.progress >= curQueue.maxProgress) {
            leaguePrepare = await GVGLeaguePrepareModel.activate(configId, myLeague.leagueCode, techId);
            // 发放连弩
            if(dicTech.type == GVG_TECH_TYPE.BATTLE_ITEM_KNIFE) {
                let members = myLeague.members||[];
                let randMembers = getRandEelm(members, dicTech.param[0]);
                for(let { roleId } of randMembers) {
                    await addGVGReward(roleId, '', myLeague.leagueCode, null, [{ id: GVG_ITEM.KNIFE, count: dicTech.param[1] }], [], ITEM_CHANGE_REASON.GVG_TECH_SEND_KNIFE);
                }
            }
            addTechActivateMessage(roleId, roleName, myLeague, techId);
        }

        // 添加 活跃
        let active = await addGVGTechActive(myLeague.leagueCode, roleId);
        checkGVGTask(serverId, roleId, sid, configId, myLeague.leagueCode, TASK_TYPE.GVG_TECH, { count: 1 });

        // 推送千机阁激活消息
        await pushTechChange(myLeague.guildCodes, true, techId, curQueue.progress, curQueue.maxProgress);

        return resResult(STATUS.SUCCESS, {
            active,
            activeTech: leaguePrepare?.activeTech||[],
            queue: leaguePrepare?.techQueue||[]
         });
    }

    // 情报页面：联军排名
    async getLeagueRankInfo(msg: {}, session: BackendSession) {

        const roleId = session.get('roleId');
        const serverId = session.get('serverId');
        const guildCode = session.get('guildCode');
        const { configId } = getGVGConfig();
        const groupKey = await getGroupKey(serverId);

        let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        const prepares = await GVGLeaguePrepareModel.getLvRank(configId);
        const leagues = await GVGLeagueModel.findByCodes(prepares.map(cur => cur.leagueCode));
        const guilds = await GuildModel.findByCodesWithoutPopulate(leagues.reduce((pre, cur) => [...pre, ...cur.guildCodes], []));
        const cities = await GVGCityModel.findGuardCity(configId, groupKey);

        let ranks: LeagueRankInInfoPage[] = [], myRank: LeagueRankInInfoPage = undefined;
        prepares.forEach((prepare, index) => {
            let league = leagues.find(cur => cur.leagueCode == prepare.leagueCode);
            if(!league) return;
            let leagueGuilds = guilds.filter(cur => cur.leagueCode == league.leagueCode);
            let leagueCe = leagueGuilds.reduce((pre, cur) => pre + cur.guildCe, 0);
            let guardCities = cities.filter(cur => cur.guardLeague == league.leagueCode).map(cur => cur.cityId);
            let data = new LeagueRankInInfoPage(index + 1, league, prepare, leagueCe, guardCities);
            if(myLeague.leagueCode == league.leagueCode) myRank = data;
            ranks.push(data);
        });

        if(!myRank) {
            let myGuilds = await GuildModel.findByCodes(myLeague.guildCodes);
            let leagueCe = myGuilds.reduce((pre, cur) => pre + cur.guildCe, 0);
            let guardCities = cities.filter(cur => cur.guardLeague == myLeague.leagueCode).map(cur => cur.cityId);
            myRank = new LeagueRankInInfoPage(0, myLeague, null, leagueCe, guardCities);
        }

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

    // 情报页面：城池占领
    async getGuardCityInfo(msg: {}, session: BackendSession) {
        
        const serverId = session.get('serverId');
    
        const { configId } = getGVGConfig();
        const groupKey = await getGroupKey(serverId);

        const cities = await GVGCityModel.findGuardCity(configId, groupKey);
        const leagueCodes = cities.map(cur => cur.guardLeague);
        const leagues = await GVGLeagueModel.findByCodes(leagueCodes);
        const prepares = await GVGLeaguePrepareModel.findByLeagueCodes(configId, leagueCodes);
        const guilds = await GuildModel.findByCodesWithoutPopulate(leagues.reduce((pre, cur) => [...pre, ...cur.guildCodes], []));

        const result: GuardCityInfoPage[] = [];
        for(let { cityId, guardLeagueCode } of result) {
            let league = leagues.find(cur => cur.leagueCode == guardLeagueCode);
            if(!league) continue;
            let prepare = prepares.find(cur => cur.leagueCode == guardLeagueCode);
            let leagueGuilds = guilds.filter(cur => cur.leagueCode == league.leagueCode);
            let leagueCe = leagueGuilds.reduce((pre, cur) => pre + cur.guildCe, 0);

            let data = new GuardCityInfoPage(cityId);
            data.setGuardLeague(league, prepare, leagueCe);
        }

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

    // 获取道具
    async debugAddLeagueItem(msg: { id: number, count: number }, session: BackendSession) {
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const sid = session.get('sid');
        const guildCode = session.get('guildCode');
        const { id, count } = msg;
        let dicGVGItem = gameData.gvgItem.get(id);
        if(!dicGVGItem) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);
        const leagueGoods = await addGVGReward(roleId, roleName, myLeague.leagueCode, sid, [{ id, count }], [], ITEM_CHANGE_REASON.DEBUG);

        return resResult(STATUS.SUCCESS, { leagueGoods });
    }

    async debugHandleCost(msg: { items: RewardInter[], leagueItems: RewardInter[] }, session: BackendSession) {
        const roleId = session.get('roleId');
        const guildCode = session.get('guildCode');
        const sid = session.get('sid');
        const { items, leagueItems } = msg;

        let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
        if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);

        const result = await handleGVGCost(roleId, myLeague.leagueCode, sid, leagueItems, items, ITEM_CHANGE_REASON.DEBUG);
        return resResult(STATUS.SUCCESS, { result });
    }
}