import { COM_BTL_QUALITY, GUILD_ACTIVITY_TYPE } from './../consts';
import * as Redis from 'redis';
import {REDIS_KEY} from '../consts'
import { GameModel } from "../db/Game";
import { promisifyAll } from 'bluebird';
import { pinus, ServerInfo } from 'pinus';
import { GuildRankParam, GuildLeader, RankParam, LineupParam } from '../domain/rank';
import { comBtlRanges } from '../pubUtils/data';
import { setRankRedisFromDb } from './rankService';
import { ServerlistModel } from '../db/Serverlist';
import moment = require('moment');
/**
 * 在服务重新启动时，将信息存入redis
 */
export async function initAllRank() {
    const serverList = await ServerlistModel.getAllServerList();
    await delKeys(REDIS_KEY.ONLINE_USERS);
    await delKeys(REDIS_KEY.USER_INFO);
    await delKeys(REDIS_KEY.GUILD_INFO);
    await delKeys(REDIS_KEY.TOP_LINEUP_INFO);
    await delKeys(REDIS_KEY.HERO_INFO);
    await delKeys(REDIS_KEY.PVP_RANK);
    await delKeys(REDIS_KEY.TOWER_RANK);
    await delKeys(REDIS_KEY.GUILD_LV_RANK);
    await delKeys(REDIS_KEY.GUILD_ACTIVE_RANK);
    await delKeys(REDIS_KEY.TOP_LINEUP_RANK);
    await delKeys(REDIS_KEY.TOP_HERO_RANK);
    await delKeys(REDIS_KEY.HERO_NUM_RANK);
    await delKeys(REDIS_KEY.USER_LV);
    await delKeys(REDIS_KEY.SUM_CE_RANK);
    // await delKeys(REDIS_KEY.DUNGEON_RANK);
    await delKeys(REDIS_KEY.DUNGEON_LINEUP);
    await delKeys(REDIS_KEY.MAIN_RANK);
    await delKeys(REDIS_KEY.MAIN_ELITE_RANK);
    await delKeys(REDIS_KEY.HERO_RANK);
    await delKeys(REDIS_KEY.SHOW_LINEUP);
    await delKeys(REDIS_KEY.PVP_RANK);

    await setRankRedisFromDb(REDIS_KEY.PVP_RANK, {});

    for(let {id} of serverList) {
        await initRank(id);
    }
}

/**
 * 分服内初始redis排行榜 
 * 
 * @param serverId 服务器
 */
export async function initRank(serverId: number) {
    // console.log('*****', 'initRank')
    await setRankRedisFromDb(REDIS_KEY.TOWER_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.GUILD_ACTIVE_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.GUILD_LV_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.TOP_LINEUP_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.TOP_HERO_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.HERO_NUM_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.USER_LV, { serverId });
    await setRankRedisFromDb(REDIS_KEY.SUM_CE_RANK, { serverId });
    // await setRankRedisFromDb(REDIS_KEY.DUNGEON_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.MAIN_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.MAIN_ELITE_RANK, { serverId });
    await setRankRedisFromDb(REDIS_KEY.HERO_RANK, { serverId });

}

/**
 * 初始化某一个排行榜，如定时器内
 * @param key redis内的key
 */
export async function initSingleRank(key: string) {

    await delKeys(key);

    if(key == REDIS_KEY.PVP_RANK) {
        await setRankRedisFromDb(key, {});
    } else {
        const serverList = await GameModel.getAllServerList();
        for(let { id } of serverList) {
            await setRankRedisFromDb(key, { serverId: id });
        }
    }
}

/** 
 * debug接口使用，直接删除排行榜数据
 * @param params serverId => guildCodes
 */
export async function delGuildActivityRank(aid: number) {
    if(aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) {
        await delKeys(REDIS_KEY.USER_GATE_ACTIVITY);
        await delKeys(REDIS_KEY.GATE_ACTIVITY);
    } else if (aid == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) {
        await delKeys(REDIS_KEY.USER_CITY_ACTIVITY);
        await delKeys(REDIS_KEY.CITY_ACTIVITY);
    } else if (aid == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) {
        await delKeys(REDIS_KEY.RACE_ACTIVITY);
    }
}

async function delKeys(key: string) {
    let keys = await redisClient().keysAsync(`${key}*`);
    for(let key of keys) {
        await redisClient().delAsync(key);
    }
    return keys
}

export async function setUserInfo(key: string, roleId: string, params: RankParam|GuildRankParam|LineupParam[]) {
    let value = JSON.stringify(params);
    return await redisClient().hsetAsync(key, roleId, value);
}

export async function updateUserInfo(key: string, roleId: string, arr: Array<{field: string, value:(string|number|GuildLeader)}>) {
    let params = await redisClient().hgetAsync(key, roleId);
    if(params) {
        let obj = JSON.parse(params);
        for(let {field, value} of arr) {
            obj[field] = value;
        }
        return await redisClient().hsetAsync(key, roleId, JSON.stringify(obj));
    }
}

/********排行榜结束 */


/**************** 寻宝相关 start */

/**
 * @description 拼接匹配分组的 key
 * @param {number} quality 品质
 * @param {number} lvRange 等级范围
 */
function getComTeamKey(quality: number, lvRange: number) {
    return `${REDIS_KEY.COM_TEAM_SEARCH_PRE}:${quality}_${lvRange}`;
}

/**
 * @description 拼接匹配分组中 member 的值
 * @param {string} roleId
 * @param {string} sid connector serverId
 * @returns
 */
function getComTeamValue(roleId: string, sid: string) {
    return `${roleId}:${sid}`;
}

/**
 * @description 把寻宝的玩家信息存入 redis
 * @export
 * @param {string} roleId
 * @param {string} sid
 * @param {Array<number>} qualityArr
 * @param {number} lvRange
 * @returns
 */
export async function setTeamSearchReq(roleId: string, sid: string, qualityArr: Array<number>, lvRange: number) {
    let cmds = [];
    qualityArr.forEach(quality => {
        if (quality) {
            cmds.push(['sadd', getComTeamKey(quality, lvRange), getComTeamValue(roleId, sid)]);
        }
    });
    const res = await redisClient().multi(cmds).execAsync();
    console.log('setTeamSearchReq: ', res);
    return res;
}

/**
 * @description 从匹配队列中删除某个用户
 * @export
 * @param {string} roleId
 * @param {string} sid
 * @param {Array<number>} qualityArr
 * @param {number} lvRange
 */
export async function rmRoleFromQueue(roleId: string, sid: string, qualityArr: Array<number>, lvRange: number) {

    let cmds = [];
    for (let q of qualityArr) {
        if (lvRange) {
            cmds.push(['srem', getComTeamKey(q, lvRange), getComTeamValue(roleId, sid)]);
        } else {
            for (let range of comBtlRanges()) {
                cmds.push(['srem', getComTeamKey(q, range), getComTeamValue(roleId, sid)]);
            }
        }
    };
    await redisClient().multi(cmds).execAsync();
}

/**
 * @description 在寻宝匹配队列中随机两个玩家
 * @export
 * @param {number} quality 队伍品质
 * @param {number} lvRange 等级范围
 * @returns
 */
export async function getTeamSearchByQuality(quality: number, lvRange: number) {
    // TODO: 操作不具有原子性
    const userInfos = await redisClient().srandmemberAsync(getComTeamKey(quality, lvRange), 2);
    console.log('getTeamSearchByQuality: ' + userInfos);
    if (!userInfos || !userInfos.length) return null;

    let res = [];
    for (let userInfo of userInfos) {
        const decodeData = `${userInfo}`.split(':');
        if (decodeData.length !== 2) return null;
        res.push({roleId: decodeData[0], sid: decodeData[1]});
    }
    console.log('getTeamSearchByQuality res: ', res);
    return res;
}

/**
 * @description 检查玩家是否在某个队列中等待寻宝匹配
 * @export
 * @param {string} roleId
 * @param {string} sid
 * @param {Array<number>} qualityArr
 * @param {number} lvRange
 * @returns
 */
export async function checkRoleInQueue(roleId: string, sid: string, qualityArr: Array<number>, lvRange: number) {
    for (let quality of qualityArr) {
        let res = await redisClient().sismemberAsync(getComTeamKey(quality, lvRange), `${roleId}:${sid}`);
        if (res) {
            return true;
        }
    };
    return false;
}

/**
 * @description 清除所有的寻宝匹配队列
 * @export
 */
export async function clearComBtlQueue() {
    for (let q of COM_BTL_QUALITY) {
        for (let lvRange of comBtlRanges()) {
            await redisClient().delAsync(getComTeamKey(q, lvRange));
        }
    }
}

export function setRedis(key: string, data: string) {
    redisClient().setAsync(key, data);
}

export async function getRedis(key: string) {
    const str =  await redisClient().getAsync(key);
    return str;
}

export async function delRedis(key: string) {
    await redisClient().delAsync(key);
}

export function redisSidKey(roleId: string) {
    return `login_roleId_${roleId}`;
}

export async function redisChannelServer(roomId: string) {
    const sid = await redisClient().hgetAsync(REDIS_KEY.CHANNEL_SERVERS, roomId);
    return sid;
}

export async function addRedisChannel(roomId: string, sid: string) {
    const result = await redisClient().hsetAsync(REDIS_KEY.CHANNEL_SERVERS, roomId, sid);
    return result;
}

export async function clearChannelServers() {
    const result = await redisClient().delAsync(REDIS_KEY.CHANNEL_SERVERS);
    return result;
}

/**
 * 玩家上线
 * @param roleId role表id
 * @param userCode user表唯一字符串标识
 * @param sid connector服的那个sid
 */
export async function roleLogin(roleId: string, userCode: string, sid: string, pkgName: string) {
    let param = { userCode, sid, pkgName };
    return await redisClient().hsetAsync(REDIS_KEY.ONLINE_USERS, roleId, JSON.stringify(param));
}

/**
 * 玩家下线
 * @param roleId role表id
 */
export async function roleLeave(roleId: string) {
    let role = await getRoleOnlineInfo(roleId);
    await redisClient().hdelAsync(REDIS_KEY.ONLINE_USERS, roleId);
    return role;
}

/**
 * 判断玩家是否在线
 * @param roleId role表id
 */
export async function isRoleOnline(roleId: string) {
    let result = await redisClient().hexistsAsync(REDIS_KEY.ONLINE_USERS, roleId);
    return !!result;
}

/**
 * 获得在线玩家userCode和sid
 * @param roleId 
 */
export async function getRoleOnlineInfo(roleId: string) {
    let str = await redisClient().hgetAsync(REDIS_KEY.ONLINE_USERS, roleId);
    if(str) {
        try {
            let result = JSON.parse(str);
            return {
                isOnline: true,
                userCode: result.userCode,
                sid: result.sid,
                pkgName: result.pkgName
            }
        } catch(e) {
            return { isOnline: false }
        }
    } else {
        return { isOnline: false }
    }
}

/**
 * 获得所有在线的玩家
 */
export async function getAllOnlineRoles() {
    const client: Redis.RedisClient = pinus.app.get('redis');
    let allRoles = await redisClient().hgetallAsync(REDIS_KEY.ONLINE_USERS);
    let result = new Array<{roleId: string, userCode: string, sid: string, pkgName: string}>();
    for(let roleId in allRoles) {
        try{ 
            let param = JSON.parse(allRoles[roleId]);
            if(param) {
                result.push({ roleId, userCode: param.userCode, sid: param.sid, pkgName: param.pkgName });
            }
        } catch(e) {
            continue;
        }
    }
    return result;
}

/**
 * 将玩家登录时间记录到
 * @param userCode 玩家user表里的userCode 
 * @param isToday 累计记录还是当日记录
 * @returns 分钟
 */
export async function incOnlineTime(userCode: string, isToday: boolean, incTime: number) {
    moment.locale('zh-cn');
    let today = moment().format('YYYYMMDD');
    let key = isToday? `${REDIS_KEY.ONLINE_TIME}:${today}`: REDIS_KEY.ONLINE_TIME;
    if(isToday) {
        let tomorrow = moment().add(1, 'days').hours(0).minutes(0).seconds(0).unix();
        let result = await redisClient().hincrbyAsync(key, userCode, incTime);
        let result2 = await redisClient().expireatAsync(key, tomorrow);
        // console.log(result2)
        return result;
    } else {
        return await redisClient().hincrbyAsync(key, userCode, incTime);
    }
}

export async function setOnlineTime(userCode: string, isToday: boolean, setTime: number) {
    moment.locale('zh-cn');
    let today = moment().format('YYYYMMDD');
    let key = isToday? REDIS_KEY.ONLINE_TIME: `${REDIS_KEY.ONLINE_TIME}:${today}`;
    if(isToday) {
        let tomorrow = moment().add(1, 'days').hours(0).minutes(0).seconds(0).format('x');
        await redisClient().expireatAsync(key, parseInt(tomorrow));
    }
    return await redisClient().hsetAsync(key, userCode, setTime);
}


// 排行榜是否存在
export async function smembersAsync(key: string) {
    const result = await redisClient().smembersAsync(key);
    return result;
}

export async function saddAsync(key: string, values: Array<string>) {
    const result = await redisClient().saddAsync(key, values);
    return result;
}

export async function sismemberAsync(key: string, value: string) {
    const result = await redisClient().sismemberAsync(key, value);
    return result;
}

export async function delAsync(key:string) {
    await redisClient().delAsync(key);
}

export async function sremAsync(key:string, member:string) {
    await redisClient().sremAsync(key, member);
}
/**************** 寻宝相关 end */

/**************** 数据库表存入缓存 */

export async function readDataBase() {
    await setServerList();
}

async function setServerList() {
    const serverList = await ServerlistModel.getAllServerList();
    await redisClient().delAsync(REDIS_KEY.DB_GAME);

    for(let { id, name } of serverList) {
        // console.log(roleId);
        await redisClient().hsetAsync(REDIS_KEY.DB_GAME, `${id}`, name);
    }
}

export async function getAllServers() {
    let servers = await  redisClient().hgetallAsync(REDIS_KEY.DB_GAME);
    let serverlist = new Array<number>();
    for(let serverStr in servers) {
        let serverId = parseInt(serverStr);
        
        if(!isNaN(serverId) && !serverlist.includes(serverId)) {
            serverlist.push(serverId);
        }
    }
    return serverlist;
}

export async function getServerName(serverId: number) {
    let name = await redisClient().hgetAsync(REDIS_KEY.DB_GAME, `${serverId}`);
    return name||'常山少年'
}

export function redisClient() {
    const client: Redis.RedisClient = pinus.app.get('redis');
    return client;
}

/**************** 数据库表end */


/*************** 将connector服插入redis *******/

export async function setConnectors(servers: ServerInfo[]) {
    for(let server of servers) {
        if(server.serverType == 'connector') {
            let { serverType, clientHost, clientPort, id } = server;
            await redisClient().hsetAsync(REDIS_KEY.SYS_SERVER, server.id, JSON.stringify({ serverType, clientHost, clientPort, id }));
        }
    }
}

export async function removeConnectors(servers: string[]) {
    for(let server of servers) {
        let hasServer = await redisClient().hgetAsync(REDIS_KEY.SYS_SERVER, server);
        if(!!hasServer) await redisClient().hdelAsync(REDIS_KEY.SYS_SERVER, server);
    }
}