package com.tsi.comm.server.controller;

import com.tsi.comm.server.config.ApplicationConfig;
import com.tsi.comm.server.config.TsiCvimServerConfig;
import com.tsi.comm.server.repository.TsiAlarmManager;
import com.tsi.comm.server.repository.TsiNodeManager;
import com.tsi.comm.server.repository.TsiSessionManager;
import com.tsi.comm.server.vo.TsiNodeVo;
import com.tsi.comm.server.xnet.NettyUtils;
import com.tsi.common.utils.TimeUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

@RestController
@RequiredArgsConstructor
@RequestMapping("")
public class TsiCommServerRestController {

    private final ApplicationConfig config;
//    private final DatabaseConfig databaseConfig;
    private final TsiCvimServerConfig serverConfig;
    private final TsiNodeManager nodeManager;
    private final TsiSessionManager sessionManager;
    private final TsiAlarmManager alarmManager;

    @GetMapping(value = "/info", produces = {"application/json; charset=utf8"})
    public String info() {
        String sep = System.lineSeparator();
        String heading = "------------------------------------------------------------------------------------------------------------------------------------------------------";

        StringBuilder sb = new StringBuilder();
        sb.append(heading).append(sep);
        sb.append(" UTIC TSI Wireless Communication Server").append(sep);
        sb.append(String.format(" Process Id: %s, Server Id: %d, Binding: %d, %s, %s",
                this.config.getProcessId(), this.serverConfig.getServerId(), this.serverConfig.getBindingPort(),
                this.config.getBootingTime(), TimeUtils.now())).append(sep);
        sb.append(heading).append(sep);
//        sb.append(String.format(" %s", this.databaseConfig.getJdbcUrl())).append(sep);
//        sb.append(heading).append(sep);

        int nodeCount = this.nodeManager.getTsiNodeVoMap().size();
        sb.append(String.format(" Report Node Sessions: %d Nodes. INTC(Install/SendNode/SendTest/SendCvim)", nodeCount)).append(sep);

        int registered = 0;
        int unknown = 0;
        int connected = 0;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));

        sb.append(String.format("   SEQ[U] %10s %4s %7s %19s %19s %9s %6s %19s  IP Address        Remote-Address", "Node ID", "INTC", "Connect", "Connect Time", "Disconnect Time", "Connected", "Closed", "Last-Recv-Time")).append(sep);
        sb.append(heading).append(sep);

        int ii = 1;
        for (Map.Entry<Long, TsiNodeVo> obj : this.nodeManager.getTsiNodeVoMap().entrySet()) {
            final TsiNodeVo node = obj.getValue();
            String check = (node.isInstalled() ? "Y" : "N");
            check = check + (node.isSendNode() ? "Y" : "N");
            check = check + (node.isSendTest() ? "Y" : "N");
            check = check + (node.isSendCvim() ? "Y" : "N");
            String unknownNode = "   ";
            if (node.isRegistered()) {
                registered++;
            }
            else {
                unknown++;
                unknownNode = "***";
            }

            String connect;
            String info;
            if (node.isConnect()) {
                connected++;
                connect = "Y";
                info = NettyUtils.getRemoteIpAddress(node.getChannel());
            }
            else {
                connect = "N";
                info = "---.---.---.---";
            }

            String connectTm = sdf.format(new Date(node.getConnectTm()));
            String disconnectTm = sdf.format(new Date(node.getDisconnectTm()));
            String lastCommTm = sdf.format(new Date(node.getLastCommTm()));

            sb.append(String.format(" %5d%3s %10s %4s %7s %19s %19s %9d %6d %19s  %-17s %s",
                    ii++, unknownNode, node.getKey(), check, connect, connectTm, disconnectTm, node.getConnectCount().get(),
                    node.getDisconnectCount().get(), lastCommTm, node.getIpAddr(), info)).append(sep);
        }
        sb.append(heading).append(sep);
        sb.append(String.format(" Total Nodes: %d EA, Registered: %d EA, Unknown: %d EA, Connected: %d EA", nodeCount, registered, unknown, connected)).append(sep);
        sb.append(String.format(" Unknown Nodes: %d EA, Unknown Node Buffers: %d EA, Unknown Ip Address: %d EA, Duplication Connect: %d EA",
                this.alarmManager.getUnknownNodeCount(), this.alarmManager.getUnknownNodeBufCount(),
                this.alarmManager.getUnknownIpAddrCount(), this.alarmManager.getDupConnectCount())).append(sep);
//        sb.append(heading).append(sep);
        sb.append(String.format(" Channel: %d EA, Session: %d EA", this.sessionManager.getChannelCount(), this.sessionManager.getCount())).append(sep);
        sb.append(heading).append(sep);

//        Set<Long> nodeIdSet = new HashSet<>();
//        ConcurrentHashMap<Channel, TsiNodeVo> channelNodeMap = this.sessionManager.getChannelNodeMap();
//        for (Map.Entry<Channel, TsiNodeVo> entry : channelNodeMap.entrySet()) {
//            Channel channel = entry.getKey();
//            TsiNodeVo nodeVo = entry.getValue();
//            Long nodeId = nodeVo.getNodeId();
//
//            TsiNodeVo dbNode = this.nodeManager.getTsiNodeVoMap().get(nodeId);
//            String ip = NettyUtils.getRemoteIpAddress(channel);
//            String dbIp = dbNode == null ? "" : dbNode.getIpAddr();
//
//            if (dbNode == null) {
//                sb.append(String.format("Not Found Node: %d, %s/%s", nodeId, ip, dbIp)).append(sep);
//            }
//            else {
//                if (!dbNode.isConnect()) {
//                    sb.append(String.format("Network state error: %d, %s/%s", nodeId, ip, dbIp)).append(sep);
//                }
//            }
//            if (nodeIdSet.contains(nodeId)) {
//                 sb.append(String.format("Dup Channel: %d %s/%s", nodeId, ip, dbIp)).append(sep);
//            } else {
//                nodeIdSet.add(nodeId);
//            }
//            if (!ip.equals(dbIp)) {
//                sb.append(String.format("IP Not Match: %d,  %s/%s", nodeId, ip, dbIp)).append(sep);
//            }
//        }
        return sb.toString();
    }

}
