package com.tsi.comm.server.repository;

import com.tsi.comm.server.vo.TsiAlarmConfigVo;
import com.tsi.comm.server.xnet.NettyUtils;
import com.tsi.common.utils.HexString;
import io.netty.channel.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@RequiredArgsConstructor
@Component
public class TsiAlarmManager {

    private final ConcurrentHashMap<String, TsiAlarmConfigVo> tsiAlarmConfigMap = new ConcurrentHashMap<>();
    private final Set<String> UNKNOWN_NODE_SET = ConcurrentHashMap.newKeySet();
    private final Set<String> UNKNOWN_NODE_BUF_SET = ConcurrentHashMap.newKeySet();
    private final Set<String> UNKNOWN_IPADDR_SET = ConcurrentHashMap.newKeySet();
    private final Set<String> DUP_CONNECT_INFO_SET = ConcurrentHashMap.newKeySet();

    public TsiAlarmConfigVo get(String code) {
        return this.tsiAlarmConfigMap.get(code);
    }
    public void put(String code, TsiAlarmConfigVo vo) {
        this.tsiAlarmConfigMap.put(code, vo);
    }

    public int size() {
        return this.tsiAlarmConfigMap.size();
    }

    public boolean checkAlarm(String code) {
        TsiAlarmConfigVo vo = get(code);
        return (vo != null && vo.isUseYn());
    }

    public int getUnknownNodeCount() {
        return this.UNKNOWN_NODE_SET.size();
    }
    public int getUnknownNodeBufCount() {
        return this.UNKNOWN_NODE_BUF_SET.size();
    }
    public int getUnknownIpAddrCount() {
        return this.UNKNOWN_IPADDR_SET.size();
    }
    public int getDupConnectCount() {
        return this.DUP_CONNECT_INFO_SET.size();
    }


    public void loggingUnknownNode(long nodeId, Channel channel) {
        final String remoteIpAddress = NettyUtils.getRemoteIpAddress(channel);
        if (this.UNKNOWN_NODE_SET.contains(remoteIpAddress)) {
            return; // 이미 등록된 IP 주소는 무시
        }
        this.UNKNOWN_NODE_SET.add(remoteIpAddress);

        final String fileName = "unknown_node";
        MDC.put("filename", fileName);
        if (nodeId > 0) {
            log.info("Node: {}, {}, unknown node id registered.", nodeId, remoteIpAddress);
        } else {
            log.info("Node: {}, {}", nodeId, remoteIpAddress);
        }
        MDC.clear();
    }
    public void loggingUnknownNodePacket(long nodeId, Channel channel, byte[] buf) {
        final String remoteIpAddress = NettyUtils.getRemoteIpAddress(channel);
        if (this.UNKNOWN_NODE_BUF_SET.contains(remoteIpAddress)) {
            return; // 이미 등록된 IP 주소는 무시
        }
        this.UNKNOWN_NODE_BUF_SET.add(remoteIpAddress);

        final String fileName = "unknown_node_packet";
        MDC.put("filename", fileName);
        log.info("Node: {}, {}, [{}]", nodeId, remoteIpAddress, HexString.fromBytes(buf));
        MDC.clear();
    }

    public void reportUnknownIp(String ipAddr) {
        if (this.UNKNOWN_IPADDR_SET.contains(ipAddr)) {
            return;
        }
        this.UNKNOWN_IPADDR_SET.add(ipAddr);

        final String fileName = "unknown_ip";
        MDC.put("filename", fileName);
        log.info("Unknown IP Address: {}", ipAddr);
        MDC.clear();
    }

    public void alarmDupConnect(Long nodeId, String ipAddr, String remoteIpAddress) {
        final String dupConnectInfo = nodeId + ":" + ipAddr + ":" + remoteIpAddress;
        if (this.DUP_CONNECT_INFO_SET.contains(dupConnectInfo)) {
            return;
        }
        this.DUP_CONNECT_INFO_SET.add(dupConnectInfo);

        final String fileName = "dup_connect";
        MDC.put("filename", fileName);
        log.info("Duplication Connect: {}", dupConnectInfo);
        MDC.clear();
    }

}
