import { KeyName, KeyNameParam, RankParam, GuildRankParam, RoleRankInfo, LineupParam, myIdInter, GeneralRankParam, ValueConfig, GuildRankInfo, RoleAndGuildRankInfo, LeagueRankParam, LeagueRankInfo } from "../domain/rank";
import { getInfoKeyByRedisKey, ROLE_SELECT, GUILD_SELECT, REDIS_KEY, HERO_SELECT, COMPOSE_FIELD_TYPE, KEY_TO_COMPOSE_FIELD, getRedisKeyByRankType, COUNTER, RANK_TYPE, PUSH_ROUTE } from "../consts";
import { redisClient, delKeys, saveLadderDefCeByData } from "./redisService";
import { RoleType, RoleModel } from "../db/Role";
import { GuildType, GuildModel } from "../db/Guild";
import { HeroModel, HeroType, HeroUpdate } from "../db/Hero";
import { PvpDefenseModel } from "../db/PvpDefense";
import { gameData } from "../pubUtils/data";
import { getSeconds, nowSeconds } from "../pubUtils/timeUtil";
import { BackendSession, pinus } from "pinus";
import { RankFirstModel, RankFirstType, RankFirstUpdateParam } from "../db/RankFirst";
import { getRandSingleEelm } from "../pubUtils/util";
import { RANK_FIRST_REWARD_STATUS } from '../consts';
import { CounterModel } from "../db/Counter";
import { ActivityTimeLimitRankModel } from "../db/ActivityTimeLimitRank";
import { sendMessageToServerWithSuc } from "./pushService";
import { LadderMatchModel } from "../db/LadderMatch";
import { completeRanks } from "./ladderService";
import { GVGVestigeSumRankModel } from "../db/GVGVestigeSumRank";
import { GVGLeagueModel, GVGLeagueType } from "../db/GVGLeague";
import { GVGVestigeLeagueRankModel } from "../db/GVGVestigeLeagueRank";
import { getDayKeyInfo } from "./gvg/gvgFightService";


/**
 * @description 排行榜相关操作
 * @export
 * @class Rank
 */
export class Rank {
    isInit: boolean = false;               // 初始排行榜
    key: REDIS_KEY;                   // 排行榜原始key
    keyName: KeyName;              // 拼接之后的key
    infoKey: REDIS_KEY;               // 玩家数据key
    extraKeys: string[];
    isUnion: boolean;              // 是否使用多个zset联合计算
    limit: number = 200;           // 排行榜长度
    unionRankLife: number = 10;
    valueConfig: ValueConfig[] = []; // 值的组合方案

    constructor(key: REDIS_KEY, keyParam: KeyNameParam, isUnion = false, limit = 200) {
        this.key = key;
        this.keyName = new KeyName(key, keyParam);
        let { infoKey, extraKey } = getInfoKeyByRedisKey(key);
        this.infoKey = infoKey;
        this.extraKeys = extraKey;
        this.isUnion = isUnion;
        this.limit = limit;
        this.setValueConfig(key);
    }

    public setIsInit(init: boolean) {
        this.isInit = init;
    }

    private setValueConfig(key: REDIS_KEY) {
        switch (key) {
            case REDIS_KEY.LADDER:
                this.valueConfig = [
                    new ValueConfig(true, 'rank', 0, false, false)
                ]; 
                break;
            case REDIS_KEY.TOP_LINEUP_RANK:
            case REDIS_KEY.TOP_LINE_SNAPSHOT:
            case REDIS_KEY.TOP_HERO_RANK:
            case REDIS_KEY.SUM_CE_RANK:
            case REDIS_KEY.SUM_CE_SNAPSHOT:
            case REDIS_KEY.HERO_RANK:
                this.valueConfig = [
                    new ValueConfig(true, 'score', 0, false, false)
                ]; 
                break;
            case REDIS_KEY.RACE_ACTIVITY:
                this.valueConfig = [
                    new ValueConfig(true, 'distance', 0, false, false),
                    new ValueConfig(false, 'time', 6, true, true),
                    new ValueConfig(false, 'durability', 3, false, false),
                ];
                break;
            case REDIS_KEY.GATE_ACTIVITY:
            case REDIS_KEY.CITY_ACTIVITY:
            case REDIS_KEY.USER_GATE_ACTIVITY:
            case REDIS_KEY.USER_CITY_ACTIVITY:
                this.valueConfig = [
                    new ValueConfig(true, 'score', 0, false, false),
                    new ValueConfig(false, 'time', 4, true, false),
                ];
                break;
            case REDIS_KEY.GUILD_LV_RANK:
                this.valueConfig = [
                    new ValueConfig(true, 'lv', 0, false, false),
                    new ValueConfig(false, 'active', 5, false, false),
                    new ValueConfig(false, 'time', 6, true, true)
                ];
                break;
            default:
                this.valueConfig = [
                    new ValueConfig(true, 'score', 0, false, false),
                    new ValueConfig(false, 'time', 10, true, true)
                ];
                break;
        }

        for(let i = 0; i < this.valueConfig.length; i++) {
            let weight = 0;
            for(let j = i + 1; j < this.valueConfig.length; j++) {
                weight += this.valueConfig[j].len;
            }
            this.valueConfig[i].setWeight(weight);
        }
    }

    /**
     * 返回字段修改
     * @param obj 
     */
    private async generFields(obj: GuildRankInfo | RoleRankInfo | LeagueRankInfo) {
        return obj;
    }

    /**
     * 从外部设置返回字段
     * @param cb 
     */
    public setGenerFieldsFun(cb: (obj: GuildRankInfo | RoleRankInfo | LeagueRankInfo) => any) {
        this.generFields = cb;
    }

    /**
     * 设置合成的排行榜的生命时长 单位s
     * @param unionRankLife 
     */
    public setUnionRankLife(unionRankLife: number) {
        this.unionRankLife = unionRankLife;
    }

    /**
     * 该排行是否为空
     * @param void
     */
    public async existsRank() {
        const result = await redisClient().existsAsync(this.keyName.getName());
        return result;
    }

    /**
     * 根据role表设置更新排行榜&玩家信息
     * @param roleId 玩家id
     * @param score 得分
     * @param timestamp 时间点
     * @param role 玩家数据库数据
     * @param isInc 得分是累加上的还是直接设置的
     */
    public async setRankWithRoleInfo(roleId: string, score: number, timestamp: number, role?: RoleType, isInc = false) {
        // 如果没有信息，更新玩家信息
        for (let infoKey of [this.infoKey, ...this.extraKeys]) {
            const hasCurUser = await redisClient().hexistsAsync(infoKey, roleId);
            if (!hasCurUser) {
                await this.generParamAndSet(infoKey, { roleId }, { role });
            }
        }
        let newScore = await this.setRank({ roleId }, [score, timestamp], isInc);

        return newScore;
    }

    /**
     * 根据军团表设置更新排行榜&军团信息
     * @param guildCode 军团code
     * @param score 得分
     * @param timestamp 时间点
     * @param guild 军团数据库
     * @param isInc 得分是累加上的还是直接设置的
     */
    public async setRankWithGuildInfo(guildCode: string, score: number, timestamp: number, guild?: GuildType, isInc = false) {
        return await this.setRankWithGuildInfoArrParam(guildCode, [score, timestamp], guild, isInc);
    }

    public async setRankWithGuildInfo2(guildCode: string, num1: number, num2: number, num3: number, guild?: GuildType, isInc = false) {
        return await this.setRankWithGuildInfoArrParam(guildCode, [num1, num2, num3], guild, isInc);
    }

    public async setRankWithGuildInfoArrParam(guildCode: string, scores: number[], guild?: GuildType, isInc = false) {
        for (let infoKey of [this.infoKey, ...this.extraKeys]) {
            const hasCurUser = await redisClient().hexistsAsync(infoKey, guildCode);
            if (!hasCurUser) {
                await this.generParamAndSet(infoKey, { guildCode }, { guild });
            }
        }
        let newScore = await this.setRank({ guildCode }, scores, isInc);

        return newScore;
    }

    public async setRankWithLeagueInfo(leagueCode: string, score: number, timestamp: number, league?: GVGLeagueType, isInc = false) {
        return await this.setRankWithLeagueInfoArrParam(leagueCode, [score, timestamp], league, isInc);
    }

    public async setRankWithLeagueInfoArrParam(leagueCode: string, scores: number[], league?: GVGLeagueType, isInc = false) {
        for (let infoKey of [this.infoKey, ...this.extraKeys]) {
            const hasCurUser = await redisClient().hexistsAsync(infoKey, leagueCode);
            if (!hasCurUser) {
                await this.generParamAndSet(infoKey, { leagueCode }, { league });
            }
        }
        let newScore = await this.setRank({ leagueCode }, scores, isInc);

        return newScore;
    }

    /**
     * 根据武将表设置更新排行榜&玩家信息
     * @param roleId 玩家id
     * @param hid 武将id
     * @param score 得分
     * @param timestamp 时间点
     * @param hero 武将数据库
     * @param isInc 得分是累加上的还是直接设置的
     */
    public async setRankWithHeroInfo(roleId: string, hid: number, score: number, timestamp: number, hero?: HeroUpdate, isInc = false) {
        // 如果没有信息，更新玩家信息
        for (let infoKey of [this.infoKey, ...this.extraKeys]) {
            await this.generParamAndSet(infoKey, { roleId, hid }, { hero });
        }
        let newScore = await this.setRank({ roleId, hid }, [score, timestamp], isInc);

        return newScore;
    }

    /**
     * 将玩家信息按顺序组成 如：roleId:hid
     * @param {{ string }} key redis key
     * @param {{ roleId?: string; guildCode?: string; hid?: number; leagueCode?: string }} param 玩家信息 
     */
    private composeFields(key: REDIS_KEY, param: myIdInter) {
        let type = KEY_TO_COMPOSE_FIELD.get(key);

        if (type == COMPOSE_FIELD_TYPE.ROLE) {
            return param.roleId;
        } else if (type == COMPOSE_FIELD_TYPE.GUILD) {
            return param.guildCode;
        } else if (type == COMPOSE_FIELD_TYPE.ROLE_HERO) {
            return `${param.roleId}:${param.hid}`;
        } else if (type == COMPOSE_FIELD_TYPE.LEAGUE) {
            return `${param.leagueCode}`;
        } else {
            return '';
        }
    }

    /**
     * 将合成了的玩家顺序解开
     * @param key redis key
     * @param field 
     * @returns {{ roleId?: string; guildCode?: string; hid?: number }}
     */
    private decodeFields(key: REDIS_KEY, field: string) {
        let type = KEY_TO_COMPOSE_FIELD.get(key);

        let arr = field.split(':');
        if (type == COMPOSE_FIELD_TYPE.ROLE) {
            return { roleId: arr[0] };
        } else if (type == COMPOSE_FIELD_TYPE.GUILD) {
            return { guildCode: arr[0] };
        } else if (type == COMPOSE_FIELD_TYPE.ROLE_HERO) {
            return { roleId: arr[0], hid: parseInt(arr[1]) };
        } else if (type == COMPOSE_FIELD_TYPE.LEAGUE) {
            return { leagueCode: arr[0] };
        } else {
            return {};
        }
    }

    /**
     * 将玩家数据设置进redis
     * @param infoKey 玩家信息的redis key
     * @param fields 玩家id
     * @param db 数据库内的数据
     */
    public async generParamAndSet(infoKey: string, fields: myIdInter, db: { role?: RoleType, guild?: GuildType, hero?: HeroUpdate, league?: GVGLeagueType }) {
        let { roleId, guildCode, hid, leagueCode } = fields;
        let { role, guild, hero, league } = db;

        if (infoKey == REDIS_KEY.USER_INFO) {
            if (!role) {
                role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.RANK, true);
                if(!role) return;
            }
            let param = new RankParam(role);
            await this.setUserInfo(infoKey, { roleId }, param);
        } else if (infoKey == REDIS_KEY.GUILD_INFO) {
            if (!guild) {
                guild = await GuildModel.findByCode(guildCode, this.keyName.serverId, GUILD_SELECT.RANK)
                if(!guild) return;
            }
            let param = new GuildRankParam(guild);
            await this.setUserInfo(infoKey, { guildCode }, param);
        } else if (infoKey == REDIS_KEY.LEAGUE_INFO) {
            if (!league) {
                league = await GVGLeagueModel.findByCode(leagueCode);
                if(!league) return;
            }
            let param = new LeagueRankParam(league);
            await this.setUserInfo(infoKey, { leagueCode }, param);
        } else if (infoKey == REDIS_KEY.TOP_LINEUP_INFO) {
            if (!role) {
                role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.RANK, true);
                if(!role) return;
            }
            let { topLineup = [] } = role;
            let heroes = await HeroModel.findByRole(roleId, [], HERO_SELECT.RANK_LINEUP);
            let arr = new Array<LineupParam>();
            for (let { hid } of topLineup) {
                let curHero = heroes.find(cur => cur.hid == hid);
                if (curHero) {
                    let param = new LineupParam(curHero);
                    arr.push(param);
                }
            }
            await this.setUserInfo(infoKey, { roleId }, arr);
        } else if (infoKey == REDIS_KEY.HERO_INFO) {
            if (!hero) {
                hero = await HeroModel.findByHidAndRole(hid, roleId, HERO_SELECT.RANK_LINEUP, true);
                if(!hero) return;
            }
            let arr = new Array<LineupParam>();
            if (hero) {
                let param = new LineupParam(hero);
                arr.push(param);
                await this.setUserInfo(infoKey, { roleId, hid }, arr);
            }
        } else if (infoKey == REDIS_KEY.DUNGEON_LINEUP) {
            if (!role) {
                role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.RANK, true);
                if(!role) return;
            }
            let { dungeonWarId, dungeonHeroes } = role;
            if (dungeonWarId > 0) {
                let cur = dungeonHeroes.find(cur => cur.battleId == dungeonWarId);
                let lineup = cur ? cur.heroes : [];
                let heroes = await HeroModel.findByRole(roleId, [], HERO_SELECT.RANK_LINEUP);
                let arr = new Array<LineupParam>();
                for (let seqId of lineup) {
                    let curHero = heroes.find(cur => cur.seqId == seqId);
                    if (curHero) {
                        let param = new LineupParam(curHero);
                        arr.push(param);
                    }
                }
                await this.setUserInfo(infoKey, { roleId }, arr);
            }
        } else if (infoKey == REDIS_KEY.SHOW_LINEUP) {
            if (!role) {
                role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.RANK, true);
                if(!role) return;
            }
            let { showLineup, topLineup = [] } = role;
            let heroes = await HeroModel.findByRole(roleId, [], HERO_SELECT.RANK_LINEUP);
            let arr = new Array<LineupParam>();
            if (!showLineup) showLineup = topLineup.map(cur => cur.hid);
            for (let hid of showLineup) {
                let curHero = heroes.find(cur => cur.hid == hid);
                if (curHero) {
                    let param = new LineupParam(curHero);
                    arr.push(param);
                }
            }
            await this.setUserInfo(infoKey, { roleId }, arr);
        }
    }

    /**
     * 设置信息
     * @param infoKey 
     * @param myId 
     * @param param 
     */
    private async setUserInfo(infoKey: REDIS_KEY, myId: myIdInter, param: RankParam | GuildRankParam | LineupParam[] | LeagueRankParam) {
        let field = this.composeFields(infoKey, myId);
        let value = JSON.stringify(param);
        return await redisClient().hsetAsync(infoKey, field, value);
    }

    /**
     * 更新排行榜数据
     * @param myId 
     * @param score 
     * @param timestamp 
     * @param isInc 
     */
    public async setRank(myId: myIdInter, scores: number[], isInc = false) {
        let oldTop = await this.getRankByRank(0, 0);
        let oldScore = oldTop.length > 0 && oldTop[0] ? oldTop[0].num : 0;
        // 更新分数
        let newScore = 0;
        if (this.isUnion) {
            newScore = await this.updateRankScoreAtom(myId, scores, isInc);
        } else {
            newScore = await this.updateRankScoreEncode(myId, scores, isInc)
        }
        this.checkFirstRankAndPush(myId, oldScore, newScore);
        return newScore;
    }

    /**
     * @description 使用将score和time合成一个字段更新分数
     * @param myId 
     * @param score 
     * @param timestamp 
     */
    private async updateRankScoreEncode(myId: myIdInter, scores: number[] = [], isInc = false) {
        let newScore = 0;
        let key = this.keyName.getName();
        let newScores: number[] = [];
        for(let index = 0; index < this.valueConfig.length; index ++) {
            let config = this.valueConfig[index];
            let score = scores[index];
            if(config.isMain) {
                if (isInc) {
                    let oldScore = await this.getMyScore(myId);
                    newScore = oldScore + score;
                } else {
                    newScore = score;
                }
                newScores.push(newScore);
            } else {
                newScores.push(score);
            }
        }

        let scoreStr = this.encodeScore(newScores);
        await redisClient().zaddAsync(key, scoreStr, this.composeFields(this.key, myId));
        return newScore
    }

    /**
     * @description 使用分两个zset更新redis中某field的值
     * @param myId 
     * @param score 
     * @param timestamp 
     * @param isInc
     * @class Rank 
     */
    private async updateRankScoreAtom(myId: myIdInter, scores: number[], isInc = false) {

        let newScore = 0;
        for(let index = 0; index < this.valueConfig.length; index ++) {
            let config = this.valueConfig[index];
            let score = scores[index];
            if(config.isMain) {
                let key = this.keyName.getName();
                // 分数zset
                if (isInc) {
                    newScore = await redisClient().zincrbyAsync(key, score, this.composeFields(this.key, myId));
                } else {
                    newScore = await redisClient().zaddAsync(key, score, this.composeFields(this.key, myId));
                }
            } else {
                let key = this.keyName.getNameWithPlus(config.name);
                if(config.isTimestamp) score = this.handleTimestamp(score, config.len);
                if(config.reverse) {
                    let pow = Math.pow(10, config.len);
                    score = pow - 1 - score;
                }
                await redisClient().zaddAsync(key, score, this.composeFields(this.key, myId));
            }
        }
        return parseInt(newScore.toString());
    }


    /**
     * @description 设置到期时间
     * @param time 到期时间，10位时间戳
     * @class Rank
     */
    public async setExpire(time: number) {
        let key = this.keyName.getName();
        let timeKey = this.keyName.getTimeName();

        await redisClient().expireatAsync(key, time);
        await redisClient().expireatAsync(timeKey, time);
    }

    public async generMyRankWithRole(roleId: string, score: number = 0, time: number = 0, role?: RoleType) {
        // 如果没有信息，更新玩家信息
        let param: RoleRankInfo;

        let hasCurUser = await redisClient().hexistsAsync(this.infoKey, roleId);
        if (!hasCurUser) {
            if (!role) {
                role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.RANK, true);
            }
            param = new RoleRankInfo(role);
            param.setInfo(0, { roleId }, score, time);
        } else {
            const info = await redisClient().hgetAsync(this.infoKey, roleId);
            const userInfo = JSON.parse(info);

            param = new RoleRankInfo(userInfo);
            param.setInfo(0, { roleId }, score, time);
        }

        for (let extraKey of this.extraKeys) {
            await this.setExInfoToParam(extraKey, param, { roleId }, { role });
        }

        return await this.generFields(param);
    }

    public async generMyRankWithGuild(guildCode: string, score: number, time: number, guild?: GuildType) {
        // 如果没有信息，更新玩家信息
        let param: GuildRankInfo;

        let hasCurUser = await redisClient().hexistsAsync(this.infoKey, guildCode);
        if (!hasCurUser) {
            if (!guild) {
                guild = await GuildModel.findByCode(guildCode, this.keyName.serverId, GUILD_SELECT.RANK);
                if(!guild) return null
            }
            param = new GuildRankInfo(guild);
            param.setInfo(0, { guildCode }, score, time);
        } else {
            const info = await redisClient().hgetAsync(this.infoKey, guildCode);
            if(!info) return null
            const guildInfo = JSON.parse(info);
            param = new GuildRankInfo(guildInfo);
            param.setInfo(0, { guildCode }, score, time);
        }

        for (let extraKey of this.extraKeys) {
            await this.setExInfoToParam(extraKey, param, { guildCode }, { guild });
        }

        return await this.generFields(param);
    }

    public async generMyRankWithGuild2(guildCode: string, score: number, time: number, active: number, guild?: GuildType) {
        // 如果没有信息，更新玩家信息
        let param: GuildRankInfo;

        let hasCurUser = await redisClient().hexistsAsync(this.infoKey, guildCode);
        if (!hasCurUser) {
            if (!guild) {
                guild = await GuildModel.findByCode(guildCode, this.keyName.serverId, GUILD_SELECT.RANK);
                if(!guild) return null
            }
            param = new GuildRankInfo(guild);
            param.setInfo2(0, { guildCode }, score, time, active);
        } else {
            const info = await redisClient().hgetAsync(this.infoKey, guildCode);
            const guildInfo = JSON.parse(info);
            if(!guildInfo) return null
            param = new GuildRankInfo(guildInfo);
            param.setInfo2(0, { guildCode }, score, time, active);
        }

        for (let extraKey of this.extraKeys) {
            await this.setExInfoToParam(extraKey, param, { guildCode }, { guild });
        }

        return await this.generFields(param);
    }

    public async generMyRankWithLeague(leagueCode: string, score: number, time: number, league?: GVGLeagueType) {
        // 如果没有信息，更新玩家信息
        let param: LeagueRankInfo;

        let hasCurUser = await redisClient().hexistsAsync(this.infoKey, leagueCode);
        if (!hasCurUser) {
            if (!league) {
                league = await GVGLeagueModel.findByCode(leagueCode);
                if(!league) return null
            }
            param = new LeagueRankInfo(league);
            param.setInfo(0, { leagueCode }, score, time);
        } else {
            const info = await redisClient().hgetAsync(this.infoKey, leagueCode);
            if(!info) return null
            const leagueInfo = JSON.parse(info);
            param = new LeagueRankInfo(leagueInfo);
            param.setInfo(0, { leagueCode }, score, time);
        }

        return await this.generFields(param);
    }

    public async generMyRankWithHero(roleId: string, hid: number, score: number, time: number, hero?: HeroType, role?: RoleType) {
        // 如果没有信息，更新玩家信息
        let param: RoleRankInfo;

        let hasCurUser = await redisClient().hexistsAsync(this.infoKey, roleId);
        if (!hasCurUser) {
            if (!role) {
                role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.RANK, true);
            }
            param = new RoleRankInfo(role);
            param.setInfo(0, { roleId, hid }, score, time);
        } else {
            const info = await redisClient().hgetAsync(this.infoKey, roleId);
            const userInfo = JSON.parse(info);

            param = new RoleRankInfo(userInfo);
            param.setInfo(0, { roleId, hid }, score, time);
        }

        for (let extraKey of this.extraKeys) {
            await this.setExInfoToParam(extraKey, param, { roleId, hid }, { hero, role });
        }

        return await this.generFields(param);
    }

    private async setExInfoToParam(extraKey: string, param: RoleRankInfo | GuildRankInfo | LeagueRankInfo, myId: myIdInter, db: { role?: RoleType, guild?: GuildType, hero?: HeroType }) {
        let { role, guild, hero } = db;

        if (extraKey == REDIS_KEY.TOP_LINEUP_INFO) {
            param = <RoleRankInfo>param;

            let hasCurUser = await redisClient().hexistsAsync(extraKey, this.composeFields(extraKey, myId));
            if (!hasCurUser) {
                if (!role) {
                    role = await RoleModel.findByRoleId(myId.roleId, ROLE_SELECT.RANK, true);
                }

                let { topLineup } = role;
                let heroes = await HeroModel.findByRole(myId.roleId, [], HERO_SELECT.HERO_DETAIL);
                let arr = new Array<LineupParam>();
                for (let { hid } of topLineup) {
                    let curHero = heroes.find(cur => cur.hid == hid);
                    if (curHero) {
                        let param = new LineupParam(curHero);
                        arr.push(param);
                    }
                }
                param.setTopLine(arr);
            } else {
                const info = await redisClient().hgetAsync(extraKey, this.composeFields(extraKey, myId));
                const infoObj = JSON.parse(info);
                param.setTopLine(infoObj);
            }
        } else if (extraKey == REDIS_KEY.HERO_INFO) {
            param = <RoleRankInfo>param;

            let hasCurUser = await redisClient().hexistsAsync(extraKey, this.composeFields(extraKey, myId));
            if (!hasCurUser) {
                if (!hero) {
                    hero = await HeroModel.findByHidAndRole(myId.hid, myId.roleId, HERO_SELECT.RANK_LINEUP);
                }
                let arr = new Array<LineupParam>();
                let lineParam = new LineupParam(hero);
                arr.push(lineParam);
                if (this.key == REDIS_KEY.HERO_RANK) {
                    param.setSingleHero(arr);
                } else {
                    param.setTopLine(arr);
                }
            } else {
                const info = await redisClient().hgetAsync(extraKey, this.composeFields(extraKey, myId));
                const infoObj = JSON.parse(info);
                if (this.key == REDIS_KEY.HERO_RANK) {
                    param.setSingleHero(infoObj);
                } else {
                    param.setTopLine(infoObj);
                }
            }
        } else if (extraKey == REDIS_KEY.DUNGEON_LINEUP) {
            param = <RoleRankInfo>param;

            let hasCurUser = await redisClient().hexistsAsync(extraKey, this.composeFields(extraKey, myId));
            if (!hasCurUser) {
                if (!role) {
                    role = await RoleModel.findByRoleId(myId.roleId, ROLE_SELECT.RANK, true);
                }
                let { dungeonWarId, dungeonHeroes } = role;
                let cur = dungeonHeroes.find(cur => cur.battleId == dungeonWarId);
                let lineup = cur ? cur.heroes : [];
                let heroes = await HeroModel.findByRole(myId.roleId, [], HERO_SELECT.RANK_LINEUP);
                let arr = new Array<LineupParam>();
                for (let seqId of lineup) {
                    let curHero = heroes.find(cur => cur.seqId == seqId);
                    if (curHero) {
                        let param = new LineupParam(curHero);
                        arr.push(param);
                    }
                }
                param.setTopLine(arr);
            } else {
                const info = await redisClient().hgetAsync(extraKey, this.composeFields(extraKey, myId));
                const infoObj = JSON.parse(info);
                param.setTopLine(infoObj);
            }
        } else if (extraKey == REDIS_KEY.SHOW_LINEUP) {
            param = <RoleRankInfo>param;

            let hasCurUser = await redisClient().hexistsAsync(extraKey, this.composeFields(extraKey, myId));
            if (!hasCurUser) {
                if (!role) {
                    role = await RoleModel.findByRoleId(myId.roleId, ROLE_SELECT.RANK, true);
                }

                let { showLineup, topLineup = [] } = role;
                let heroes = await HeroModel.findByRole(myId.roleId, [], HERO_SELECT.HERO_DETAIL);
                let arr = new Array<LineupParam>();
                if (!showLineup) showLineup = topLineup.map(cur => cur.hid);
                for (let hid of showLineup) {
                    let curHero = heroes.find(cur => cur.hid == hid);
                    if (curHero) {
                        let param = new LineupParam(curHero);
                        arr.push(param);
                    }
                }
                param.setTopLine(arr);
            } else {
                const info = await redisClient().hgetAsync(extraKey, this.composeFields(extraKey, myId));
                const infoObj = JSON.parse(info);
                param.setTopLine(infoObj);
            }
        }
    }

    public async getRankListWithMyRank(myId: myIdInter, isReverse = true) {
        let ranks = await this.getRankByRange('+inf', '-inf', isReverse);
        let newRanks = [], newMyRank: any;
        let myRank = ranks.find(cur => {
            return cur.isMyInfo(myId);
        });
        if (this.generFields) {
            for (let rank of ranks) {
                let n = await this.generFields(rank);
                if(n) newRanks.push(n);
            }
            if (myRank) {
                newMyRank = await this.generFields(myRank);
            }
        }

        return { myRank: newMyRank, ranks: newRanks }
    }

    /**
     * 获取排行榜原始数据
     * @param from 
     * @param to 
     */
    public async getRankDataByRankWithoutDetail(from: number | string = '+inf', to: number | string = '-inf') {
        let key = this.keyName.getName();
        if (this.isUnion) {
            key = await this.generateUnionRank();
        }

        const rankFromDb = await redisClient().zrevrangebyscoreAsync(key, from, to, "WITHSCORES");
        let ranks: { rank: number, myId: {roleId?: string, guildCode?: string, hid?: number}, scores: number[] }[] = [];

        let num = 0;
        for (let ii = 0; ii < rankFromDb.length; ii += 2) {
            if (num >= this.limit) break;

            const field = rankFromDb[ii];
            let myId = this.decodeFields(this.key, field);
            const scores = this.decodeScore(rankFromDb[ii + 1]);

            ranks.push({ rank: num, myId, scores });
            num++;
        }
        return ranks
    }

    // 获取区间里的排行榜，格式 {rank, field, score}[]
    public async getRankByRangeRaw(max: number | string = '+inf', min: number | string = '-inf', isReverse = true) {
        let ranks: { rank: number, field: string, scores: number[] }[] = [];
        let key = this.keyName.getName();
        if (this.isUnion) {
            key = await this.generateUnionRank();
        }

        const rankFromDb = isReverse? 
            (await redisClient().zrevrangebyscoreAsync(key, max, min, "WITHSCORES")):
            (await redisClient().zrangebyscoreAsync(key, min, max, "WITHSCORES"));

        let num = 0;
        for (let ii = 0; ii < rankFromDb.length; ii += 2) {
            if (num >= this.limit) break;
            ranks.push({ rank: Math.floor(ii / 2) + 1, field: rankFromDb[ii], scores: this.decodeScore(rankFromDb[ii + 1]) });
            num++;
        }
        return ranks
    }

    public async getRankByRange(max: number | string = '+inf', min: number | string = '-inf', isReverse = true) {
        let raws = await this.getRankByRangeRaw(max, min, isReverse);

        let ranks = new Array<RoleRankInfo | GuildRankInfo | LeagueRankInfo>();
        let l = 1;
        for (let { field, scores } of raws) {
            let param = await this.getParam(l, field, scores);
            if(param) {
                ranks.push(param); l++;
            }
        }
        return ranks
    }

    public async getParam(rank: number, field: string, scores: number[]) {
        let myId = this.decodeFields(this.key, field);

        const info = await redisClient().hgetAsync(this.infoKey, this.composeFields(this.infoKey, myId));
        const userInfo = JSON.parse(info);
        if(!userInfo) return null;
        
        let param: RoleRankInfo | GuildRankInfo | LeagueRankInfo;
        if (this.infoKey == REDIS_KEY.USER_INFO) {
            if (this.key != REDIS_KEY.LADDER && this.key != REDIS_KEY.GVG_VESTIGE_MEMBER && nowSeconds() - userInfo.updatedAt > 2 * 30 * 24 * 60 * 60) {
                return null;
            }
            param = new RoleRankInfo(userInfo);
            param.setInfo(rank, myId, scores[0], scores[1]);
        } else if (this.infoKey == REDIS_KEY.GUILD_INFO) {
            if(this.key == REDIS_KEY.GUILD_LV_RANK|| this.key == REDIS_KEY.RACE_ACTIVITY) {
                param = new GuildRankInfo(userInfo);
                param.setInfo2(rank, myId, scores[0], scores[1], scores[2]);
            } else {
                param = new GuildRankInfo(userInfo);
                param.setInfo(rank, myId, scores[0], scores[1]);
            }
        } else if (this.infoKey == REDIS_KEY.LEAGUE_INFO) {
            param = new LeagueRankInfo(userInfo);
            param.setInfo(rank, myId, scores[0], scores[1]);

        }

        for (let extraKey of this.extraKeys) {
            await this.setExInfoToParam(extraKey, param, myId, {});
        }
        return param
    }

    public async getRankByRank(start: number, end: number) {

        let ranks = new Array<RoleRankInfo | GuildRankInfo | LeagueRankInfo>();
        let key = this.keyName.getName();
        if (this.isUnion) {
            key = await this.generateUnionRank();
        }

        const rankFromDb = await redisClient().zrevrangeAsync(key, start, end, "WITHSCORES");

        // console.log(key, start, end, rankFromDb)

        let num = 0;
        for (let ii = 0; ii < rankFromDb.length; ii += 2) {
            if (num >= this.limit) break;
            let param = await this.getParam(Math.floor(ii / 2) + 1, rankFromDb[ii], this.decodeScore(rankFromDb[ii + 1]));
            if(param) ranks.push(param);
            num++;
        }
        return ranks
    }


    // 获取我的排名
    public async getMyRank(myId: myIdInter) {
        let key = this.keyName.getName();
        if (this.isUnion) {
            key = await this.generateUnionRank();
        }
        // console.log('**getMyRank',key, this.composeFields(this.key, myId), this.key, myId)
        let myRank = await redisClient().zrevrankAsync(key, this.composeFields(this.key, myId));
        if (!myRank && myRank != 0) {
            return 0;
        } else {
            return myRank + 1;
        }
    }

    // 获取排名第几名的信息
    public async getUserByRank(rank: number) {
        let key = this.keyName.getName();
        let myRank = await redisClient().zrevrangeAsync(key, rank - 1, rank - 1);
        return myRank;
    }


    // 获取排名第几名的信息
    public async getMyScore(myId: myIdInter) {
        let key = this.keyName.getName();
        let score = await redisClient().zscoreAsync(key, this.composeFields(this.key, myId));
        if (!score) score = 0;
        if (!this.isUnion) {
            let result = this.decodeScore(score.toString());
            score = result[0];
        }
        return parseInt(score.toString());
    }

    // 从排行榜中移除
    public async removeFromRank(myId: myIdInter) {
        let key = this.keyName.getName();
        await redisClient().zremAsync(key, this.composeFields(this.key, myId));

        return true;
    }

    private async generateUnionRank() {
        let unionKey = this.keyName.getUnionName(); // 联合的key

        let keys = [], weights = [];
        this.valueConfig.forEach(({ isMain, name, weight }) => {
            if(isMain) {
                keys.push(this.keyName.getName());
            } else {
                keys.push(this.keyName.getNameWithPlus(name));
            }
            weights.push(Math.pow(10, weight))

        })

        await redisClient().zunionstoreAsync(unionKey, 2, ...keys, 'WEIGHTS', ...weights);
        await redisClient().expireAsync(unionKey, this.unionRankLife); // 10秒更新一次
        return unionKey;
    }

    // 有序排行综合时间和得分排序
    private encodeScore(scores: number[]) {
        let encodeResult = 0;
        // console.log('#### decoencodeResultdeScore', this.key, scores, this.valueConfig);
        this.valueConfig.forEach(({ name, reverse, isTimestamp, len, weight }, index) => {
            let score = scores[index];
            // console.log('*** 1', name, len, weight, score, encodeResult)
            if(isTimestamp) score = this.handleTimestamp(score, len);
            // console.log('*** 2', name, len, weight, score, encodeResult)
            if(!reverse) {
                encodeResult += score * Math.pow(10, weight);
            } else {
                let pow = Math.pow(10, len);
                encodeResult += (pow - 1 - score) * Math.pow(10, weight);
            }
            // console.log('*** 3', name, len, weight, score, encodeResult)
        })
        return encodeResult
    }

    private decodeScore(num: string) {
        let _num = parseInt(num);
        let scores: number[] = [];
        this.valueConfig.forEach(({ name, reverse, isTimestamp, len, weight }) => {
            let pow = Math.pow(10, weight);
            let score = Math.floor(_num / pow);
            // console.log('*** 1', name, len, weight, score)
            _num -= pow * score;
            if(isTimestamp) score = this.handleTimestamp(score, len);
            // console.log('*** 2', name, len, weight, score)
            if(reverse) {
                let pow = Math.pow(10, len);
                score = pow - 1 - score;
            }
            // console.log('*** 3', name, len, weight, score)
            scores.push(score);
        })
        // console.log('#### decodeScore', this.key, scores, this.valueConfig);
        return scores;
    }

    private handleTimestamp(timestamp: number = 0, len: number) {
        let l = timestamp.toString().length;
        if (l > len) {
            timestamp = Math.floor(timestamp / Math.pow(10, l - len));
        }
        return timestamp
    }

    private async getFirstUserInfo(myId: myIdInter) {
        const info = await redisClient().hgetAsync(this.infoKey, this.composeFields(this.infoKey, myId));
        if(!info) return null
        const playerInfo = JSON.parse(info);

        if (this.infoKey == REDIS_KEY.USER_INFO) {
            let userInfo = new RankParam(playerInfo);
            return { userInfo }
        } else if (this.infoKey == REDIS_KEY.GUILD_INFO) {
            let guildInfo = new GuildRankInfo(playerInfo);
            return { guildInfo }
        }
        return false
    }

    // 首通
    private async checkFirstRankAndPush(myId: myIdInter, oldScore: number, newScore: number) {
        let ts = this;
        if (ts.isInit) return;

        let serverId = this.keyName.serverId;
        let dicRank = gameData.rank.find(({ id }) => {
            let redisKey = getRedisKeyByRankType(id);
            return redisKey == ts.key
        });
        if(!dicRank) return;

        let infos = await this.getFirstUserInfo(myId);
        if(!infos) return;

        let { userInfo, guildInfo } = infos
        let rankFirstRecs: (RankFirstType & { status: number })[] = [];
        for(let [id, { rankId, condition }] of gameData.generalRankReward) {
            // console.log(rankId, dicRank.id, oldScore, condition, newScore);
            let hasRankFirst = await getRankFirstRewardById(serverId, id);
            if(!hasRankFirst && dicRank.id == rankId && oldScore < condition && newScore >= condition) {
                let rankFirstRec = await RankFirstModel.createRankFirst(serverId, id, rankId, { userInfo, guildInfo });
                if(rankFirstRec && getSeconds(rankFirstRec.createdAt) == getSeconds(rankFirstRec.updatedAt)) {
                    await setRankFirst(rankFirstRec);
                    rankFirstRecs.push({ ... rankFirstRec, status: 1});
                }
            }
        }
            
        if(rankFirstRecs.length > 0) {
            await sendMessageToServerWithSuc(serverId, PUSH_ROUTE.RANK_TOP_UPDATE, { ranks: rankFirstRecs }, true);
        }
    }
}

/**
 * 从其他服获取首通信息
 * @param serverId 
 * @param id dic_zyz_rankingType的id
 * @returns 
 */
async function getRankFirstRewardById(serverId: number, id: number) {
    let rankFirst: RankFirstType;
    if(pinus.app.getServerType() == 'role') {
        rankFirst = pinus.app.get('rankFirstRewards').get(serverId)?.get(id);
    } else {
        let roleServers = pinus.app.getServersByType('role');
        let server = getRandSingleEelm(roleServers);
        rankFirst = await pinus.app.rpc.role.roleRemote.getRankFirstById.toServer(server.id, serverId, id);
    }
    return rankFirst;
}

async function setRankFirst(rankFirstRec: RankFirstType) {
    let roleServers = pinus.app.getServersByType('role');
    for(let server of roleServers) {
        pinus.app.rpc.role.roleRemote.setRankFirst.toServer(server.id, rankFirstRec);
    }
}

/**
 * 从数据库内获取排行榜存入redis
 * @param type 排行榜类型
 * @param serverId 分服
 */
export async function setRankRedisFromDb(type: string, args?: { serverId?: number, groupId?: number }) {
    if (type == REDIS_KEY.TOWER_RANK) {
        let serverId = args.serverId;
        let ranks = await RoleModel.getRank('tower', serverId, ROLE_SELECT.RANK);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let role of ranks) {
            // console.log(roleId);
            if(role.towerLv > 1) {
                await r.setRankWithRoleInfo(role.roleId, role.towerLv - 1, role.towerUpTime ? role.towerUpTime.getTime() : 0, role);
            }
        }
    } else if (type == REDIS_KEY.GUILD_ACTIVE_RANK) {
        let serverId = args.serverId;
        let ranks = await GuildModel.getRank(type, serverId);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let guild of ranks) {
            await r.setRankWithGuildInfo(guild.code, guild.activeWeekly, guild.activeUpdateTime, guild);
        }
    } else if (type == REDIS_KEY.GUILD_LV_RANK) {

        let serverId = args.serverId;
        let ranks = await GuildModel.getRank(type, serverId);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let guild of ranks) {
            await r.setRankWithGuildInfoArrParam(guild.code, [guild.lv, guild.activeWeekly, guild.activeUpdateTime], guild);
        }
    } else if (type == REDIS_KEY.PVP_RANK) {
        let seasonNum = await CounterModel.getCounter(COUNTER.PVP_SEASON_NUM);
        if(seasonNum > 0) {
            let keyName = new KeyName(type, { seasonNum })
            await delKeys(keyName.getName());
            let ranks = await PvpDefenseModel.getRank(seasonNum);//获得全服前1000名的排名，加入到redis中

            let r = new Rank(type, { seasonNum });
            r.setIsInit(true);
            for (let { roleId, role: _role, score, updatedAt } of ranks) {
                let role = <RoleType>_role;
                if (!role) {
                    continue;
                }
                await r.setRankWithRoleInfo(roleId, score, updatedAt.getTime(), role);
            }
        }
    } else if (type == REDIS_KEY.TOP_LINEUP_RANK) {
        let serverId = args.serverId;
        let ranks = await RoleModel.getRank('topLineup', serverId, ROLE_SELECT.RANK);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let role of ranks) {
            // console.log(roleId);
            await r.setRankWithRoleInfo(role.roleId, role.topLineupCe, role.updatedAt.getTime(), role);
        }
    } else if (type == REDIS_KEY.TOP_HERO_RANK) {
        let serverId = args.serverId;
        let ranks = await HeroModel.getAllRank(serverId, HERO_SELECT.RANK_LINEUP);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let hero of ranks) {
            await r.setRankWithHeroInfo(hero.roleId, hero.hid, hero.ce, hero.updatedAt.getTime(), hero);
        }
    } else if (type == REDIS_KEY.HERO_NUM_RANK) {
        let serverId = args.serverId;
        let ranks = await RoleModel.getRank('heroNum', serverId, ROLE_SELECT.RANK);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let role of ranks) {
            await r.setRankWithRoleInfo(role.roleId, role.heroNum, role.heroNumUpdatedAt, role);
        }
    } else if (type == REDIS_KEY.USER_LV) {
        let serverId = args.serverId;
        let ranks = await RoleModel.getRank('lv', serverId, ROLE_SELECT.RANK);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let role of ranks) {
            await r.setRankWithRoleInfo(role.roleId, role.lv, role.updatedAt.getTime(), role);
        }
    } else if (type == REDIS_KEY.SUM_CE_RANK) {
        let serverId = args.serverId;
        let ranks = await RoleModel.getRank('ce', serverId, ROLE_SELECT.RANK);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let role of ranks) {
            await r.setRankWithRoleInfo(role.roleId, role.ce, role.updatedAt.getTime(), role);
        }
    } else if (type == REDIS_KEY.DUNGEON_RANK) {
        let serverId = args.serverId;
        let ranks = await RoleModel.getRank('dungeon', serverId, ROLE_SELECT.RANK);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let role of ranks) {
            await r.setRankWithRoleInfo(role.roleId, role.dungeonWarId, role.dungeonUpdatedAt, role);
        }
    } else if (type == REDIS_KEY.MAIN_RANK) {
        let serverId = args.serverId;
        let ranks = await RoleModel.getRank('main', serverId, ROLE_SELECT.RANK);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let role of ranks) {
            await r.setRankWithRoleInfo(role.roleId, role.mainWarId, role.mainUpdatedAt, role);
        }
    } else if (type == REDIS_KEY.MAIN_ELITE_RANK) {
        let serverId = args.serverId;
        let ranks = await RoleModel.getRank('mainElite', serverId, ROLE_SELECT.RANK);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let role of ranks) {
            await r.setRankWithRoleInfo(role.roleId, role.mainEliteWarId, role.mainEliteUpdatedAt, role);
        }
    } else if (type == REDIS_KEY.HERO_RANK) {
        let serverId = args.serverId;

        for (let [hid] of gameData.recruit) {
            let ranks = await HeroModel.getRank(hid, serverId, HERO_SELECT.RANK_LINEUP);
            let r = new Rank(type, { serverId, hid });
            r.setIsInit(true);
            for (let hero of ranks) {
                await r.setRankWithHeroInfo(hero.roleId, hid, hero.ce, hero.updatedAt.getTime(), hero);
            }
        }
    } else if (type == REDIS_KEY.LADDER) {
        let serverId = args.serverId;
        let ranks = await LadderMatchModel.findAll(serverId);
        let r = new Rank(type, { serverId });
        r.setIsInit(true);
        for (let rank of ranks) {
            let role = <RoleType>rank.role;
            await r.setRankWithRoleInfo(rank.roleId, rank.rank, 0, role);
            await saveLadderDefCeByData(rank.roleId, rank);
        }
    } else if (type == REDIS_KEY.GVG_VESTIGE_MEMBER_ALL) {
        let ranks = await GVGVestigeSumRankModel.findRankByGroupId();
        for(let { _id: groupKey, arr, roleIds } of ranks) {
            let roles = await RoleModel.findByRoleIds(roleIds, ROLE_SELECT.RANK);
            let r = new Rank(type, { groupKey, day: getDayKeyInfo() });
            r.setIsInit(true);
            for(let { roleId, score, updatedAt } of arr) {
                let role = roles.find(cur => cur.roleId == roleId);
                if(role) {
                    await r.setRankWithRoleInfo(roleId, score, updatedAt.getTime(), role);
                }
            }
        }
    } else if (type == REDIS_KEY.GVG_VESTIGE_LEAGUE) {
        let ranks = await GVGVestigeLeagueRankModel.findRank();
        for(let { _id: groupKey, arr, leagueCodes } of ranks) {
            let leagues = await GVGLeagueModel.findByCodes(leagueCodes);
            let r = new Rank(type, { groupKey, day: getDayKeyInfo() });
            r.setIsInit(true);
            for(let { leagueCode, score, updatedAt } of arr) {
                let league = leagues.find(cur => cur.leagueCode == leagueCode);
                if(league) {
                    await r.setRankWithLeagueInfo(leagueCode, score, updatedAt.getTime(), league);
                }
            }
        }
    }
}

/**
 * 获取排行榜总览
 * @param role 玩家数据
 * @param serverId 所在服务器
 */
export async function getGeneralRank(role: RoleType & { rankReceived: number[] }, serverId: number) {
    let { rankReceived = [] } = role;

    let result: (GeneralRankParam & {general: number})[] = [];

    for (let { id, general } of gameData.rank) {
        let redisKey = getRedisKeyByRankType(id);
        if (redisKey) {
            let received = rankReceived.filter(rewardId => {
                let dic = gameData.generalRankReward.get(rewardId);
                return dic && dic.rankId == id;
            });
            let r = new Rank(redisKey, { serverId }, false, 1);
            let ranks = await r.getRankByRange('+inf', '-inf', id != RANK_TYPE.LADDER);
            // if (ranks.length > 0) {
            let param = new GeneralRankParam(id, ranks[0], general, received);
            result.push({...param, general});
        }
    }
    return result;
}

/**
 * 获取排行榜总览
 * @param role 玩家数据
 * @param serverId 所在服务器
 */
 export async function getRankFirstReward(role: RoleType & { rankReceived: number[] }, serverId: number) {
    let { rankReceived = [] } = role;

    let result: (RankFirstUpdateParam & {status: number})[] = [];

    for (let [id, { rankId: type } ] of gameData.generalRankReward) {
        let rankFirst = await getRankFirstRewardById(serverId, id);
       
        if(rankFirst) {
            let status = rankReceived.includes(id)?RANK_FIRST_REWARD_STATUS.RECEIVED: RANK_FIRST_REWARD_STATUS.CAN_RECEIVE;
            result.push({...rankFirst, status});
        } else {
            result.push({ id, type,  status: RANK_FIRST_REWARD_STATUS.WAITING });
        }
    }
    return result;
}

export async function getRankInHandler(redisKey: REDIS_KEY, type: RANK_TYPE, keyParam: KeyNameParam, session: BackendSession) {
    
    const roleId = session.get('roleId');
    const serverId = session.get('serverId');
    const guildCode = session.get('guildCode');

    let r = new Rank(redisKey, keyParam);
    r.setGenerFieldsFun((obj => {
        let result = new RoleAndGuildRankInfo(obj.rank, obj.num);
        if(type == RANK_TYPE.LADDER) {
            result = new RoleAndGuildRankInfo(obj.num, 0);
        }
        if(obj instanceof GuildRankInfo) {
            result.setGuildInfo(obj);
        }
        if(obj instanceof RoleRankInfo) {
            result.setUserInfo(obj);
        }
        return result
    }));

    let { ranks, myRank } = await r.getRankListWithMyRank({ roleId, guildCode }, type != RANK_TYPE.LADDER);
    if (!myRank) {
        let role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.RANK, true);
        if (type == RANK_TYPE.TOP_LINTUP) {
            myRank = await r.generMyRankWithRole(roleId, role.topLineupCe, 0, role);
        } else if (type == RANK_TYPE.TOP_HERO) {
            let hero = await HeroModel.getMyTopHero(roleId, HERO_SELECT.RANK_LINEUP);
            myRank = await r.generMyRankWithHero(roleId, hero.hid, hero.ce, 0, hero, role);
        } else if (type == RANK_TYPE.HERO_NUM) {
            myRank = await r.generMyRankWithRole(roleId, role.heroNum, role.heroNumUpdatedAt, role);
        } else if (type == RANK_TYPE.USER_LV) {
            myRank = await r.generMyRankWithRole(roleId, role.lv, role.updatedAt.getTime(), role);
        } else if (type == RANK_TYPE.SUM_CE) {
            myRank = await r.generMyRankWithRole(roleId, role.ce, role.updatedAt.getTime(), role);
        } else if (type == RANK_TYPE.TOWER) {
            myRank = await r.generMyRankWithRole(roleId, role.towerLv - 1, role.towerUpTime?.getTime() || 0, role);
        // } else if (type == RANK_TYPE.DUNGEON) {
        //     myRank = await r.generMyRankWithRole(roleId, role.dungeonWarId, role.dungeonUpdatedAt, role);
        } else if (type == RANK_TYPE.MAIN) {
            myRank = await r.generMyRankWithRole(roleId, role.mainWarId, role.mainUpdatedAt, role);
        } else if (type == RANK_TYPE.MAIN_ELITE) {
            myRank = await r.generMyRankWithRole(roleId, role.mainEliteWarId, role.mainEliteUpdatedAt, role);
        } else if (type == RANK_TYPE.GUILD_LV) {
            if(role.hasGuild) {
                let guild = await GuildModel.findByCode(guildCode, serverId);
                myRank = await r.generMyRankWithGuild2(roleId, guild.lv, guild.activeWeekly, guild.lvUpdateTime, guild);
            }
        } else if (type == RANK_TYPE.GUILD_FUND) {
            if(role.hasGuild) {
                let limitRank = await ActivityTimeLimitRankModel.findByCode(serverId, keyParam.activityId, guildCode);
                myRank = await r.generMyRankWithGuild(guildCode, limitRank?.score||0, limitRank?.time);
            }
        } else if (type == RANK_TYPE.LADDER) {
            myRank = await r.generMyRankWithRole(roleId, 0, 0, role);
        }
    }
    // if(type == RANK_TYPE.LADDER) {
        ranks = completeRanks(ranks);
    // }
    return { ranks, myRank }
}