import { EXTERIOR } from "../pubUtils/dicParam";
import { RoleUpdate, RoleType } from "../db/Role";
import { GuildUpdateParam } from "../db/Guild";
import { HeroUpdate, } from "../db/Hero";
import { getSeconds } from "../pubUtils/timeUtil";
import { prop } from "@typegoose/typegoose";
import { pick } from "underscore";
import { RANK_TYPE, REDIS_KEY } from "../consts";
import { GVGLeagueType } from "../db/GVGLeague";

// 排行榜返回玩家值
export class RankParam {
    @prop({ required: true })
    roleName: string = "";

    @prop({ required: true })
    serverId: number = 0;

    @prop({ required: true })
    lv: number = 0;

    @prop({ required: true })
    guildName: string = "";

    @prop({ required: true })
    head: number = EXTERIOR.EXTERIOR_FACE;

    @prop({ required: true })
    frame: number = EXTERIOR.EXTERIOR_FACECASE;

    @prop({ required: true })
    spine: number = EXTERIOR.EXTERIOR_APPEARANCE;

    @prop({ required: true })
    title: number = 1;

    @prop({ required: true })
    ce: number = 0;

    @prop({ required: true })
    topLineupCe: number = 0;

    @prop({ required: true })
    updatedAt?: number = 0;

    constructor(role: RoleUpdate|RankParam) {
        if(role.roleName) this.roleName = role.roleName;
        if(role.lv) this.lv = role.lv;
        if(role.head) this.head = role.head;
        if(role.frame) this.frame = role.frame;
        if(role.spine) this.spine = role.spine;
        if(role.title) this.title = role.title;
        if(role.guildName) this.guildName = role.guildName||"";
        if(role.ce) this.ce = role.ce;
        if(role.topLineupCe) this.topLineupCe = role.topLineupCe;
        if(role.updatedAt) {
            if(typeof role.updatedAt == 'number') {
                this.updatedAt = role.updatedAt;
            } else {
                this.updatedAt = getSeconds(role.updatedAt);
            }
        }
        if(role.serverId) this.serverId = role.serverId;
    }
}

export class GuildLeader {
    @prop({ required: true })
    roleId: string;

    @prop({ required: true })
    roleName: string;

    @prop({ required: true })
    title: number;

    @prop({ required: true })
    lv: number;

    @prop({ required: true })
    head: number;

    @prop({ required: true })
    frame: number;

    @prop({ required: true })
    spine: number;

    @prop({ required: true })
    serverId: number;

    constructor(leader: { roleId: string, roleName: string, title: number, lv: number, head: number, frame: number, spine: number, serverId: number}) {
        this.roleId = leader.roleId;
        this.roleName = leader.roleName;
        this.title = leader.title;
        this.lv = leader.lv;
        this.head = leader.head;
        this.frame = leader.frame;
        this.spine = leader.spine;
        this.serverId = leader.serverId;
    }
}

// 排行榜返回玩家值
export class LineupParam {
    @prop({ required: true })
    hid: number;

    @prop({ required: true })
    skinId: number;

    @prop({ required: true })
    star: number;

    @prop({ required: true })
    colorStar: number;

    @prop({ required: true })
    lv: number;

    @prop({ required: true })
    quality: number;

    @prop({ required: true })
    job: number;

    constructor(hero: HeroUpdate) {
        this.hid = hero.hid;
        this.skinId = hero.skinId;
        this.star = hero.star;
        this.colorStar = hero.colorStar;
        this.lv = hero.lv;
        this.quality = hero.quality;
        this.job = hero.job;
    }
}

export class RoleRankInfo extends RankParam {
    rank: number = 1;
    roleId: string = "";
    num: number = 0;
    time: number = 0;
    hero: LineupParam[];
    lineup: LineupParam[];
    
    setInfo(rank: number, myId: myIdInter, num: number, time: number) {
        this.rank = rank;
        this.roleId = myId.roleId;
        this.num = num;
        this.time = time;
    }

    isMyInfo(myId: myIdInter) {
        return this.roleId == myId.roleId;
    }

    setTopLine(lineup: LineupParam[]){
        this.lineup = lineup;
    }

    setSingleHero(hero: LineupParam[]){
        this.hero = hero;
    }
}

// 公会排行榜返回值
export class GuildRankParam {
    @prop({ required: true })
    icon: number;

    @prop({ required: true })
    name: string;

    @prop({ required: true })
    lv: number;

    @prop({ required: true })
    memberCnt: number;

    @prop({ required: true, _id: false })
    leader: GuildLeader;

    @prop({ required: true })
    guildCe: number;

    constructor(guild: GuildUpdateParam) {
        this.icon = guild.icon;
        this.name = guild.name;
        this.lv = guild.lv;
        let leader = <RoleType>guild.leader;
        let _leader = new GuildLeader(leader);
        this.leader = _leader;
        this.guildCe = guild.guildCe;
        this.memberCnt = guild.memberCnt;
    }
}


export class GuildRankInfo extends GuildRankParam {
    rank: number;
    code: string;
    num: number;
    time: number;
    num1?: number;
    num2?: number;
    
    setInfo(rank: number, myId: myIdInter, num: number, time: number) {
        this.rank = rank;
        this.code = myId.guildCode;
        this.num = num;
        this.time = time;
    }

    setInfo2(rank: number, myId: myIdInter, num: number, num1: number, num2: number) {
        this.rank = rank;
        this.code = myId.guildCode;
        this.num = num;
        this.num1 = num1;
        this.num2 = num2;
    }

    isMyInfo(myId: myIdInter) {
        return this.code == myId.guildCode;
    }
}


export class LeagueLeader {
    @prop({ required: true })
    roleId: string;

    @prop({ required: true })
    roleName: string;

    @prop({ required: true })
    guildName: string;

    @prop({ required: true })
    serverId: number;

    constructor(leader: { roleId: string, roleName: string, guildName: string, serverId: number}) {
        this.roleId = leader.roleId;
        this.roleName = leader.roleName;
        this.guildName = leader.guildName;
        this.serverId = leader.serverId;
    }
}

// 联军信息
export class LeagueRankParam {
    @prop({ required: true })
    icon: number;

    @prop({ required: true })
    name: string;

    @prop({ required: true, _id: false })
    leader: LeagueLeader;

    constructor(league: GVGLeagueType) {
        this.icon = league.icon;
        this.name = league.name;
        let leader = <RoleType>league.leader;
        let _leader = new LeagueLeader(leader);
        this.leader = _leader;
    }
}

// LeagueRankParam显示到排行榜界面上的信息
export class LeagueRankInfo extends LeagueRankParam {
    rank: number;
    code: string;
    num: number;
    time: number;
    
    setInfo(rank: number, myId: myIdInter, num: number, time: number) {
        this.rank = rank;
        this.code = myId.leagueCode;
        this.num = num;
        this.time = time;
    }

    isMyInfo(myId: myIdInter) {
        return this.code == myId.leagueCode;
    }
}

export class RoleAndGuildRankInfo {
    rank: number;
    num: number;
    userInfo?: RankParam & { roleId: string };
    lineup?: LineupParam[];
    guildInfo?: GuildRankParam & { code: string, active?: number };
    hasUser: boolean = false;
    
    constructor(rank: number, num: number) {
        this.rank = rank;
        this.num = num;
    }

    setUserInfo(role: RoleRankInfo) {
        this.userInfo = pick(role, ['roleId', 'roleName', 'head', 'frame', 'spine', 'lv', 'title', 'guildName', 'ce', 'topLineupCe', 'serverId']);
        this.lineup = role.lineup;
        this.hasUser = true;
    }

    setGuildInfo(guild: GuildRankInfo) {
        this.guildInfo = pick(guild, ['code', 'icon', 'name', 'leader', 'guildCe', 'lv', 'memberCnt']);
        this.guildInfo.active = guild.num1;
        this.hasUser = true;
    }

    isMyInfo(myId: myIdInter) {
        if(this.userInfo && myId.roleId) {
            if(this.userInfo.roleId == myId.roleId) return true;
        }
        if(this.guildInfo && myId.guildCode) {
            if(this.guildInfo.code == myId.guildCode) return true;
        }
        return false;
    }

    setByField(roleId: string, roleName: string, head: number, frame: number, spine: number, lv: number, title: number, guildName: string, ce: number, topLineupCe: number, serverId: number) {
        this.userInfo = { roleId, roleName, head, frame, spine, lv, title, guildName, ce, topLineupCe, serverId }
    }
}

export class SimpleGuildRankParam {
    rank: number = 0;
    code: string = "";
    name: string = "";
    num: number = 0;
    
    constructor(rank: number, code: string, name: string, num: number) {
        this.rank = rank;
        this.code = code;
        this.name = name;
        this.num = num;
    }
}

export class SimpleRoleRankParam {
    rank: number;
    roleId: string;
    roleName: string;
    num: number;

    constructor(rank: number, roleId: string, roleName: string, num: number) {
        this.rank = rank;
        this.roleId = roleId;
        this.roleName = roleName;
        this.num = num;
    }
}

export class KeyName {
    key: string;
    serverId?: number;
    guildCode?: string;
    cityId?: number;
    hid?: number;
    seasonNum?: number;
    activityId?: number;
    index?: number;  // 军团活动第几期
    vestigeId?: number;
    groupKey?: string;
    day?: string;
    configId?: number;

    constructor(key: string, param: KeyNameParam) {
        this.key = key;
        if(param.serverId) this.serverId = param.serverId;
        if(param.guildCode) this.guildCode = param.guildCode;
        if(param.cityId) this.cityId = param.cityId;
        if(param.hid) this.hid = param.hid;
        if(param.seasonNum) this.seasonNum = param.seasonNum;
        if(param.activityId) this.activityId = param.activityId;
        if(param.index) this.index = param.index;
        if(param.vestigeId) this.vestigeId = param.vestigeId;
        if(param.groupKey) this.groupKey = param.groupKey;
        if(param.day) this.day = param.day;
        if(param.configId) this.configId = param.configId;
    }

    public getName() {
        switch(this.key) {
            case REDIS_KEY.TOP_LINEUP_RANK:
            case REDIS_KEY.TOP_HERO_RANK:
            case REDIS_KEY.HERO_NUM_RANK:
            case REDIS_KEY.SUM_CE_RANK:
            case REDIS_KEY.USER_LV:
            case REDIS_KEY.MAIN_RANK:
            case REDIS_KEY.MAIN_ELITE_RANK:
            case REDIS_KEY.GUILD_LV_RANK:
            case REDIS_KEY.GUILD_ACTIVE_RANK:
            case REDIS_KEY.TOWER_RANK:
            case REDIS_KEY.LADDER:
                return `${this.key}:${this.serverId}`;
            case REDIS_KEY.HERO_RANK:
                return `${this.key}:${this.serverId}:${this.hid}`;
            case REDIS_KEY.PVP_RANK:
                return `${this.key}:${this.seasonNum}`;
            case REDIS_KEY.GATE_ACTIVITY:
            case REDIS_KEY.RACE_ACTIVITY:
                return `${this.key}:${this.serverId}:${this.index}`;
            case REDIS_KEY.CITY_ACTIVITY:
                return `${this.key}:${this.serverId}:${this.index}:${this.cityId}`;
            case REDIS_KEY.USER_CITY_ACTIVITY:
            case REDIS_KEY.USER_GATE_ACTIVITY:
                return `${this.key}:${this.serverId}:${this.index}:${this.guildCode}`;
            case REDIS_KEY.GUILD_FUND:
            case REDIS_KEY.SUM_CE_SNAPSHOT:
            case REDIS_KEY.TOP_LINE_SNAPSHOT:
                return `${this.key}:${this.serverId}:${this.activityId}`;
            case REDIS_KEY.GVG_VESTIGE_MEMBER:
                return `${this.key}:${this.day}:${this.groupKey}:${this.vestigeId}`;
            case REDIS_KEY.GVG_VESTIGE_MEMBER_ALL:
                return `${this.key}:${this.day}:${this.groupKey}`;
            case REDIS_KEY.GVG_VESTIGE_LEAGUE:
                return `${this.key}:${this.day}:${this.groupKey}`;
            case REDIS_KEY.GVG_BATTLE_RANK:
                return `${this.key}:${this.configId}:${this.groupKey}`;
            case REDIS_KEY.GVG_BATTLE_LEAGUE_RANK:
                return `${this.key}:${this.configId}:${this.groupKey}`;
            case REDIS_KEY.GVG_BATTLE_LEAGUE_RANK_BY_CITY:
                return `${this.key}:${this.configId}:${this.groupKey}:${this.cityId}`;
            default:
                 return this.key;
        }
    }

    public getNameWithPlus(...plus: string[]) {
        let res = this.getName();
        for(let p of plus) {
            res += `:${p}`;
        }
        return res;
    }

    public getTimeName() {
        return this.getNameWithPlus('time');
    }

    public getUnionName() {
        return this.getNameWithPlus('union');
    }
}

export type KeyNameParam = Partial<KeyName>;

export class ValueConfig {
    isMain: boolean;   // 最主要的排序，getRank的num字段，isInc的时候只有这个会用zinc
    name: string
    len: number;  // 长度
    weight?: number;  // 按顺序排之后，其他参数的len加和
    reverse: boolean = false; // 例如时间戳，需要倒转的那种
    isTimestamp: boolean = false; // 是否是时间戳

    constructor(isMain: boolean, name: string, len: number, reverse = false, isTimestamp = false) {
        this.isMain = isMain;
        this.name = name;
        this.len = len;
        this.reverse = reverse;
        this.isTimestamp = isTimestamp;
    }

    setWeight(weight: number) {
        this.weight = weight;
    }
}

export interface myIdInter {
    roleId?: string;
    guildCode?: string;
    hid?: number;
    leagueCode?: string;
}

// 排行榜总览左边的数据
export class GeneralRankParam {
    type: number;  // 排行榜id
    hasUser: boolean = false;
    userInfo?: RankParam;
    num: number = 0;
    received: number[];

    constructor(type: number, rankInfo: RoleRankInfo|GuildRankInfo|LeagueRankInfo, general: number, received?: number[]) {
        this.type = type;
        if(general == 1) {
            let rank = rankInfo? (type == RANK_TYPE.LADDER? rankInfo.num: rankInfo.rank): 0;
            if(rank == 1) {
                if(rankInfo instanceof RoleRankInfo) {
                    this.userInfo = pick(rankInfo, ['roleId', 'roleName', 'head', 'frame', 'spine', 'guildName', 'ce', 'title', 'lv', 'topLineupCe', 'serverId']);
                    this.hasUser = true;
                }
                if(rankInfo instanceof GuildRankInfo) {
    
                    let leaderInfo = pick(rankInfo.leader, ['roleId', 'roleName', 'head', 'frame', 'spine', 'ce', 'title', 'lv', 'serverId']);
                    this.userInfo = {
                        ...leaderInfo, guildName: rankInfo.name, ce: rankInfo.guildCe, topLineupCe: rankInfo.guildCe
                    }
                    this.hasUser = true;
                }
                this.num = rankInfo?.num||0;
            }
        }
        this.received = received;
    }
}