package com.wecloud.im.ws.manager;

import com.alibaba.fastjson.JSON;
import com.wecloud.im.ws.cache.UserStateListener;
import com.wecloud.im.ws.model.ClientInfo;
import com.wecloud.im.ws.utils.RedisUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.util.RamUsageEstimator;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * channel内容管理，在线、离线等信息在channel里
 * @author lixiaozhong
 */
@Component
@Slf4j
public class ChannelManager {

    /**
     * client端对应channel的数据
     * key: appId-clientId-platform
     * value: channel对象
     */
    public static final Map<String, ClientInfo> SESSION_INFO_MAP = new ConcurrentHashMap<>();

    /**
     * CLIENT_ID,是客户端的字符串id
     */
    public static final AttributeKey<Long> CLIENT_ID = AttributeKey.valueOf("ci");

    public static final AttributeKey<Long> APPLICATION_ID = AttributeKey.valueOf("ai");

    public static final AttributeKey<Integer> READ_IDLE_TIMES = AttributeKey.valueOf("readIdleTimes");

    /**
     * LANGUAGE
     */
    AttributeKey<String> LANGUAGE = AttributeKey.valueOf("la");

    /**
     * APP_VERSIONn
     */
    AttributeKey<String> APP_VERSION = AttributeKey.valueOf("av");
    AttributeKey<String> TOKEN = AttributeKey.valueOf("to");
    AttributeKey<String> DEVICEID = AttributeKey.valueOf("dc");
    public static final AttributeKey<Integer> PLATFORM = AttributeKey.valueOf("pt");

    /**
     * client上线
     * userID绑定channel
     * @param clientId
     * @param platform
     * @param channel
     */
    public void online(Long clientId, Integer platform, NioSocketChannel channel) {
        String longChannelId = channel.id().asLongText();
        log.info("保存本地连接clientId {} platform {}", clientId, platform);
        this.putSessionInfoMap(clientId, platform, channel);

        UserStateListener.triggerOnlineEvent(clientId, platform, longChannelId);
    }

    /**
     * 下线移除channel
     *
     * @param clientId
     * @param platform
     * @param channelHandlerContext
     */
    public void offline(Long clientId, Integer platform, ChannelHandlerContext channelHandlerContext) {

        String longChannelId = channelHandlerContext.channel().id().asLongText();

        // 关掉连接
        channelHandlerContext.close();

        ClientInfo oldChanel = ChannelManager.SESSION_INFO_MAP.get(genKeyForSessionInfoMap(clientId, platform));
        if(oldChanel != null && oldChanel.getNioSocketChannel().isActive()) {
            // 活跃的连接，可能是新建的，不能处理
            log.info("连接还是活跃的，不下线处理 clientId {},oldChanel {}", clientId, oldChanel.getNioSocketChannel().id().asLongText());
            return;
        }

        // 移除本地维护的channel
        delSessionInfoMap(clientId, platform);

        UserStateListener.triggerOfflineEvent(clientId, platform, longChannelId);

    }

    public static String genKeyForSessionInfoMap(Long clientId, Integer platform) {
        return clientId + RedisUtils.SPLIT + platform;
    }

    private void putSessionInfoMap(Long clientId, Integer platform, NioSocketChannel channel) {
        ClientInfo clientInfo = new ClientInfo();
        clientInfo.setDeviceId("");
        clientInfo.setNioSocketChannel(channel);
        clientInfo.setToken("");
        log.info("本地存缓存key {},大小 {}", genKeyForSessionInfoMap(clientId, platform), RamUsageEstimator.humanSizeOf(clientInfo));

        ChannelManager.SESSION_INFO_MAP.put(genKeyForSessionInfoMap(clientId, platform), clientInfo);
    }

    private void delSessionInfoMap(Long clientId, Integer platform) {
        log.info("本地清缓存key {}", genKeyForSessionInfoMap(clientId, platform));
        ChannelManager.SESSION_INFO_MAP.remove(genKeyForSessionInfoMap(clientId, platform));
        log.info("删除map后，本地缓存结果 {}", JSON.toJSONString(ChannelManager.SESSION_INFO_MAP.get(genKeyForSessionInfoMap(clientId, platform))));
    }

}
