package org.dromara.tcpfuwu.server;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;

import org.dromara.shebei.service.IOpsSbLiebiaoService;
import org.dromara.tcpfuwu.domain.DeviceCache;
import org.dromara.tcpfuwu.handler.DeviceHandler;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 统一TCP服务器（发送Modbus请求前必须验证心跳状态）
 */
@Component
@Slf4j
public class UnifiedTcpServer {

    @Value("${tcp.server.port:12345}")
    private int tcpPort;
    @Value("${tcp.server.heartbeat-timeout: 60000}")
    private int heartbeatExpireMs;

    // 线程池：处理设备连接
    private ExecutorService clientExecutor;
    // 服务器Socket
    private ServerSocket serverSocket;
    // 设备缓存
    private final Map<String, DeviceCache> deviceCache = new ConcurrentHashMap<>();
    // 缓存清理线程
    private ScheduledExecutorService cacheCleaner;
    // 服务运行状态
    private volatile boolean isRunning = false;

    @Autowired
    private IOpsSbLiebiaoService sbLiebiaoService;


    /**
     * 初始化方法：Spring容器启动后自动调用
     */
    @PostConstruct
    public void start() {
        // 新增：判断是否已启动，避免重复执行
        if (isRunning) {
            System.out.println("【TCP服务】已启动，无需重复执行");
            return;
        }
        try {
            System.out.printf("【TCP服务启动】尝试绑定端口：%d%n", tcpPort);
            // 初始化服务器Socket
            ServerSocket serverSocket = new ServerSocket();
            // 允许端口复用（即使处于TIME_WAIT状态，也能重新绑定）
            serverSocket.setReuseAddress(true);
            // 绑定端口（替换原有的 new ServerSocket(tcpPort)）
            serverSocket.bind(new InetSocketAddress(tcpPort));
            this.serverSocket = serverSocket;
            // 初始化线程池（处理设备连接）
            clientExecutor = Executors.newCachedThreadPool(r -> {
                Thread thread = new Thread(r);
                thread.setName("tcp-client-handler-" + thread.getId());
                thread.setDaemon(true); // 守护线程，随主线程退出
                return thread;
            });
            // 初始化缓存清理线程
            initCacheCleaner();

            isRunning = true;
            System.out.printf("【TCP服务启动成功】监听端口：%d%n", tcpPort);

            // 启动接受连接的线程
            new Thread(this::acceptConnections, "tcp-acceptor").start();

        } catch (Exception e) {
            System.err.println("【TCP服务启动失败】" + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 接受设备连接的循环
     */
    private void acceptConnections() {
        while (isRunning) {
            try {
                // 阻塞等待设备连接
                Socket clientSocket = serverSocket.accept();
                String deviceAddr = clientSocket.getInetAddress() + ":" + clientSocket.getPort();
                System.out.printf("%n【设备上线】地址：%s%n", deviceAddr);

                // 初始化设备缓存
                DeviceCache cache = new DeviceCache();
                cache.setCreateTime(System.currentTimeMillis());
                deviceCache.put(deviceAddr, cache);

                // 提交设备处理任务
                clientExecutor.submit(() ->
                    new DeviceHandler(clientSocket, deviceAddr, cache, deviceCache,sbLiebiaoService).handle()
                );

            } catch (Exception e) {
                if (isRunning) { // 非关闭状态下的异常
                    System.err.println("【连接接受异常】" + e.getMessage());
                }
            }
        }
    }

    /**
     * 初始化缓存清理线程
     */
    private void initCacheCleaner() {
        cacheCleaner = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread thread = new Thread(r);
            thread.setName("cache-cleaner");
            thread.setDaemon(true);
            return thread;
        });

        // 每20秒清理一次过期设备
        cacheCleaner.scheduleAtFixedRate(() -> {
            long currentTime = System.currentTimeMillis();
            for (Map.Entry<String, DeviceCache> e : deviceCache.entrySet()) {
                String deviceAddr = e.getKey();
                DeviceCache cache = e.getValue();
                // 判断是否过期：未收到过心跳 或 超过过期时间
                boolean isExpired = cache.getLastHeartbeatTime() == 0
                    ? (currentTime - cache.getCreateTime() > heartbeatExpireMs)
                    : (currentTime - cache.getLastHeartbeatTime() > heartbeatExpireMs);

                if (isExpired && !cache.isExpired()) {
                    cache.setExpired(true);
                    deviceCache.remove(deviceAddr);
                    System.out.printf("【设备过期】设备地址：%s，已清理缓存%n", deviceAddr);
                }
            }
        }, 0, 20, TimeUnit.SECONDS);
    }

    /**
     * 销毁方法：Spring容器关闭前自动调用
     */
    @PreDestroy
    public void stop() {
        isRunning = false;
        System.out.println("【TCP服务开始关闭】");

        // 关闭服务器Socket
        try {
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
        } catch (Exception e) {
            System.err.println("【关闭ServerSocket异常】" + e.getMessage());
        }

        // 关闭线程池
        if (clientExecutor != null) {
            clientExecutor.shutdown();
        }

        // 关闭缓存清理线程
        if (cacheCleaner != null) {
            cacheCleaner.shutdown();
        }

        // 清理设备缓存
        deviceCache.clear();

        System.out.println("【TCP服务已关闭】");
    }
}
