import { Channel, pinus } from "pinus";
import { CHANNEL_PREFIX, PUSH_BATCH, PUSH_INTERVAL, PUSH_ROUTE, STATUS } from "../consts";
import { genCode, resResult } from "../pubUtils/util";
import { getCityChannelSid, getGuildChannelSid, getWorldChannelSid, groupRoomId, getGroupShopSid, getGVGAreaChannelSid, getGVGAreaTeamChannelSid, getGVGCityTeamChannelSid } from "./chatService";
import { getAllOnlineRoles, getAllServers, getRoleOnlineInfo } from "./redisService";
import { errlogger, infologger } from '../util/logger';
import { MsgEncrypt } from "../pubUtils/sysUtil";
import { isSkipEncode } from "../pubUtils/sdkUtil";
import { isDevelopEnv } from "./utilService";

export async function sendMessageToAllWithSuc(route: string, data: any, filterCb?: ({ lv, topLineupCe }) => boolean) {
    await sendMessageToAll(route, resResult(STATUS.SUCCESS, data), filterCb);
}

export async function sendMessageToAll(route: string, data: any, filterCb?: ({ lv, topLineupCe }) => boolean) {
    let allOnlineUsers = await getAllOnlineRoles();
    if(filterCb) {
        allOnlineUsers = allOnlineUsers.filter(filterCb);
    }
    let n = Math.ceil(allOnlineUsers.length / PUSH_BATCH); // 一共多少批
    let sendToUser = (i: number) => {
        let users = allOnlineUsers.slice(i * PUSH_BATCH, (i + 1) * PUSH_BATCH - 1);
        let uids = users.map(cur => ({ uid: cur.roleId, sid: cur.sid }));
        sendMessageToUsers(route, data, uids);
    }
    let i = -1;
    sendToUser(++i);
    let interval = setInterval(() => {
        if (++i < n) {
            sendToUser(i);
        } else {
            clearInterval(interval);
        }
    }, PUSH_INTERVAL);
}

export async function sendMessageToAllServersWithSuc(route: string, data: any) {
    let servers = await getAllServers();
    for(let serverId of servers) {
        await sendMessageToServerWithSuc(serverId, route, data);
    }
}

export async function sendMessageToServerWithSuc(serverId: number, route: string, data: any, isBatch = false) {
    await sendMessageToServer(serverId, route, resResult(STATUS.SUCCESS, data), isBatch);
}

export async function sendMessageToServer(serverId: number, route: string, data: any, isBatch = false) {
    let channelSid = await getWorldChannelSid(serverId);
    let roomId = groupRoomId(CHANNEL_PREFIX.WORLD, serverId);
    await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, data, isBatch);
}

export async function sendMessageToGuildWithSuc(guildCode: string, route: string, data: any) {
    await sendMessageToGuild(guildCode, route, resResult(STATUS.SUCCESS, data));
}

export async function sendMessageToGuild(guildCode: string, route: string, data: any) {
    let channelSid = await getGuildChannelSid(guildCode);
    let roomId = groupRoomId(CHANNEL_PREFIX.GUILD, guildCode);
    await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, data);
}

export async function sendMessageToGVGAreaWithSuc(groupKey: string, areaId: number, route: string, data: any) {
    let channelSid = await getGVGAreaChannelSid(groupKey, areaId);
    let roomId = groupRoomId(CHANNEL_PREFIX.GVG_AREAS, `${groupKey}_${areaId}`);
    await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data));
}

export async function sendMessageToGVGAreaByTeamWithSuc(groupKey: string, areaId: number, route: string, data: any) {
    let channelSid = await getGVGAreaTeamChannelSid(groupKey, areaId);
    let roomId = groupRoomId(CHANNEL_PREFIX.GVG_AREA_BY_TEAM, `${groupKey}_${areaId}`);
    await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data));
}

export async function sendMessageToGVGCityWithSuc(groupKey: string, cityId: number, route: string, data: any) {
    let channelSid = await getGVGCityTeamChannelSid(groupKey, cityId);
    let roomId = groupRoomId(CHANNEL_PREFIX.GVG_CITY, `${groupKey}_${cityId}`);
    await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data));
}

export async function sendMessageToCityWithSuc(serverId: number, cityId: number, route: string, data: any) {
    await sendMessageToCity(serverId, cityId, route, resResult(STATUS.SUCCESS, data));
}

export async function sendMessageToCity(serverId: number, cityId: number, route: string, data: any) {
    let channelSid = await getCityChannelSid(serverId, cityId);
    let roomId = groupRoomId(CHANNEL_PREFIX.CITY, `${serverId}_${cityId}`);
    await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, data);
}

export async function sendMessageToGroupShopWithSuc(route: string, data: any) {
    let channelSid = await getGroupShopSid();
    let roomId = groupRoomId(CHANNEL_PREFIX.GROUP_SHOP);
    await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data));
}

export async function sendMessageToUserWithSuc(roleId: string, route: string, data: any, sid?: string) {
    await sendMessageToUser(roleId, route, resResult(STATUS.SUCCESS, data), sid);
}

export async function sendMessageToUser(roleId: string, route: string, data: any, sid?: string) {
    let uids = [];
    if (!sid) {
        let onlineUser = await getRoleOnlineInfo(roleId);
        sid = onlineUser.sid;
    }
    if (!!sid) {
        uids.push({ uid: roleId, sid });
        sendMessageToUsers(route, data, uids);  
    }
}

export async function sendMessageToUsersWithSuc(route: string, data: any, uids: { uid: string, sid: string }[]) {
    await sendMessageToUsers(route, resResult(STATUS.SUCCESS, data), uids);
}

// 推送给个人的方法收束于这个函数
export async function sendMessageToUsers(route: string, data: any, uids: { uid: string, sid: string }[]) {
    if(uids.length > 0) {
        pinus.app.get('channelService').pushMessageByUids(route, encryptMsg(route, data), uids);
        infologger.debug(`pushMessage route: ${route} data: ${JSON.stringify(data)} members: ${uids.map(obj => obj.uid).join()}`);
    }
}

export async function sendMessageToTeam(teamCode: string, route: string, data: any) {
    const channel = pinus.app.get('channelService').getChannel(teamCode);
    sendMessageToChannel(channel, route, resResult(STATUS.SUCCESS, data));
}

/**
 * 
 * @param user 
 */
 export function addUserToTeamChannel(teamCode: string, isCreate: boolean, roleId: string, sid: string) {
     let channel = pinus.app.get('channelService').getChannel(teamCode, isCreate);
     addUserToChannel(channel, roleId, sid);
     return channel
}

export function addUserToChannel(channel: Channel, roleId: string, sid: string) {
    const users = channel.getMembers();
    if (users.indexOf(roleId) === -1) {
        channel.add(roleId, sid);
    }
}

export function sendMessgeToChannelByBatch(channel: Channel, route: string, data: any) {
    let members = channel.getMembers();
    if(members.length > PUSH_BATCH) {
        let n = Math.ceil(members.length / PUSH_BATCH); // 一共多少批
        // console.log(n)
        let i = -1;
        let interval = setInterval(() => {
            if (++i < n) {
                let uidlist = members.slice(i * PUSH_BATCH, (i + 1) * PUSH_BATCH - 1);
                let uids: { uid: string, sid: string }[] = [];
                for (let uid of uidlist) {
                    uids.push(channel.getMember(uid));
                }
                sendMessageToUsers(route, data, uids);
            } else {
                clearInterval(interval);
            }
        }, PUSH_INTERVAL);
    } else {
        sendMessageToChannel(channel, route, data);
    }
}

 // 抽下下来pushMessage收束
export function sendMessageToChannel(channel: Channel, route: string, data: any) {
    if(channel.getMembers().length <= 0) return;
    channel.pushMessage(route, encryptMsg(route, data));
    infologger.debug(`pushMessage route: ${route} data: ${JSON.stringify(data)} members: ${channel.getMembers().join()}`);
}

export function delTeamChannel(teamCode: string) {
    let channel = pinus.app.get('channelService').getChannel(teamCode);
    if(!!channel) channel.destroy();
}

export function removeFromTeamChannel(teamCode: string, roleId: string) {
    let channel = pinus.app.get('channelService').getChannel(teamCode);
    if(!channel) return null;
    
    let users: string[] = channel.getMembers();
    if (users.indexOf(roleId) !== -1) {
        channel.removeMember(roleId);
    }
}

function getKvFromMemory() {
    let aesKey = pinus.app.get('aesKey');
    let aesIV = pinus.app.get('aesIV');
    let originK = pinus.app.get('originK');
    let originV = pinus.app.get('originV');
    let kvRefTime = pinus.app.get('kvRefTime');
    let now = new Date().setMinutes(0, 0, 0);
    if(!kvRefTime || now - kvRefTime >= 60 * 60 * 1000) {
        originK = genCode(24);
        originV = genCode(16);
        let msgEncrypt = new MsgEncrypt({ k: originK, v: originV });
        ({ aesKey, aesIV } = msgEncrypt.getEncodeKv());

        setKvToRemote(originK, originV, aesKey, aesIV, now);
    }
    return { aesKey, aesIV, originK, originV, now }
}

function setKvToRemote(originK: string, originV: string, aesKey: string, aesIV: string, now: number) {
    pinus.app.rpc.activity.activityRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
    pinus.app.rpc.battle.battleRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
    pinus.app.rpc.chat.chatRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
    pinus.app.rpc.connector.connectorRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
    pinus.app.rpc.guild.guildRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
    pinus.app.rpc.order.orderRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
    pinus.app.rpc.role.roleRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
    pinus.app.rpc.systimer.systimerRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
}

export function setKvToMemory(originK: string, originV: string, aesKey: string, aesIV: string, now: number) {
    pinus.app.set('originK', originK);
    pinus.app.set('originV', originV);
    pinus.app.set('aesKey', aesKey);
    pinus.app.set('aesIV', aesIV);
    pinus.app.set('kvRefTime', now);
}

function encryptMsg(event: string, json: any) {
    if(checkNotEncryptRoute(event)) return json
    let { aesKey, aesIV, originK, originV } = getKvFromMemory();
    let msgEncrypt = new MsgEncrypt({ originK, originV });
    let data = msgEncrypt.encryptMsg(json);
    return { data, k: aesKey, v: aesIV }
}

function checkNotEncryptRoute(event: string) {
    return isSkipEncode(isDevelopEnv()) || [
        PUSH_ROUTE.PUSH_CURRENT_TIME,    // onPushCurrentTime 推送时间
        PUSH_ROUTE.RACE_START,           // onRaceStart 粮草先行开始
        PUSH_ROUTE.GUILD_ACTIVITY_END,   // onGuildActivityEnd 军团活动结束
        PUSH_ROUTE.GUILD_RACE_UPDATE,    // onRaceHorseUpdate 粮草先行状态
        PUSH_ROUTE.GUILD_RACE_EVENT,     // onRaceEventUpdate 更新木马事件
        PUSH_ROUTE.TEAMMATE_ACT,         // onTeammateAct 寻宝队友行动
        PUSH_ROUTE.CITY_ACT_RANK,        // onGuildCityRankUpdate 诸侯混战排行榜
        PUSH_ROUTE.GUILD_CITY_ACT_HP,    // onGuildCityGateHpUpdate 诸侯混战城门血条
        PUSH_ROUTE.GUILD_GATE_ACT_HP,    // onGuildGateHpUpdate 蛮夷入侵城门血条
        PUSH_ROUTE.GATE_ACT_RANK,        // onGuildGateRankUpdate 蛮夷入侵排行榜
        PUSH_ROUTE.BOSS_HP_UPDATE,       // onBossHpUpdate 演武台更新
        PUSH_ROUTE.DIVIDEND_UPDATE,      // onDividendsUpdate 拍卖行分红更新
        PUSH_ROUTE.AUCTION_OVER,         // onAuctionOver 拍卖价格超过
        PUSH_ROUTE.GUILD_BOSS_ENCOURAGE, // onGuildBossEncourage 鼓舞
        PUSH_ROUTE.GVG_TEAM_ATTACKED,    // onTeamAttacked 当队伍受到攻击
        PUSH_ROUTE.GVG_MY_TEAM_ATTACKED,  // onMyTeamAttacked 当队伍受到攻击
        PUSH_ROUTE.GVG_AREA_SPINE_CHANGE, // onAreaSpinesChange 可见区域内spine的变动，每隔5秒会下发
        PUSH_ROUTE.GVG_AREA_POINT_CHANGE, // onMyAreaPointChange 积分点上的驻守人变更
        PUSH_ROUTE.GVG_PLAYER_AREA_ADD,   // onPlayerAddToArea 积分点上的驻守人变更
        PUSH_ROUTE.GVG_PLAYER_LEAVE_AREA, // onPlayerLeaveArea 积分点上的驻守人变更
        PUSH_ROUTE.GVG_CITY_RANK_UPDATE,  // onGVGCityRankUpdate 城池积分排名
        PUSH_ROUTE.GVG_SPINE_ATTACKED,    // onSpinesAttacked 队伍在地图上受到攻击
    ].indexOf(event) != -1
}