package cn.iocoder.yudao.module.pms.websocket;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 适配 Nginx 代理的 WS 客户端管理器（仅管理连接，不处理发送）
 */
@Component
@Slf4j
public class WsClientManager {

    /** 存储客户端ID -> WS会话的映射（线程安全） */
    private final Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
    /** 核心线程池（处理连接、重连） */
    private final ExecutorService executor = Executors.newFixedThreadPool(10); // 适配多连接

    @Resource
    private WsAddressService wsAddressService;

    /**
     * 项目启动时初始化所有动态连接（自动开始接收消息）
     */
//    @PostConstruct
//    public void initAllConnections() {
//        executor.submit(this::connectAll);
//    }

    /**
     * 批量连接所有动态获取的 WSS 地址（Nginx 代理）
     */
    private void connectAll() {
        // 1. 从接口/数据库查询所有需要连接的配置
        List<WsClientConfig> configs = wsAddressService.listAllWsConfigs();
        if (configs.isEmpty()) {
            log.warn("⚠️ 未查询到任何Nginx代理WSS连接配置，无需建立连接");
            return;
        }

        // 2. 为每个配置创建独立连接（每个连接独立接收消息）
        for (WsClientConfig config : configs) {
            executor.submit(() -> connect(config));
        }
    }

    /**
     * 连接单个 WSS 地址（适配 Nginx 代理）
     */
    private void connect(WsClientConfig config) {
        try {
            String clientId = config.getClientId();
            // 避免重复连接
            if (sessionMap.containsKey(clientId) && sessionMap.get(clientId).isOpen()) {
                log.info("⚠️ [{}] 已存在有效Nginx代理WSS连接，无需重复创建", clientId);
                return;
            }

            // 核心调整1：创建支持 WSS 的客户端（适配 Nginx 代理）
            StandardWebSocketClient wsClient = createWssEnabledClient();
            // 核心调整2：解析 WSS 地址，确保路径正确（适配 Nginx 转发到 172.21.10.65:8080/ws/）
            URI wssUri = URI.create(config.getWsUrl());
            // 创建专属处理器（仅接收消息）
            DynamicWsClientHandler handler = new DynamicWsClientHandler(config, this);

            // 发起 WSS 连接（芋道框架原生能力 + SSL 配置）
            Future<WebSocketSession> future = wsClient.doHandshake(handler, String.valueOf(wssUri));
            // 阻塞等待连接结果（确保连接建立）
            WebSocketSession session = future.get();
            log.info("🔌 [{}] WSS连接请求已发送，路径：{}，代理转发到：http://172.21.10.65:8080/ws/{}",
                    clientId, wssUri.getPath(), clientId);
        } catch (Exception e) {
            log.error("🔌 [{}] 连接Nginx代理WSS失败", config.getClientId(), e);
            // 触发重连，保证消息接收链路不中断
            reconnect(config);
        }
    }

    /**
     * 创建支持 WSS 的客户端（配置 SSL 上下文，适配 Nginx 代理）
     */
    private StandardWebSocketClient createWssEnabledClient() {
        StandardWebSocketClient wsClient = new StandardWebSocketClient();
        // 核心：设置 SSL 上下文（解决 Nginx 证书校验问题）
        wsClient.getUserProperties().put(
                "javax.net.ssl.SSLContext",
                WssSslConfigUtil.createIgnoreVerifySSLContext()
        );
        // 设置 SSL 参数（适配 SNI 扩展）
        wsClient.getUserProperties().put(
                "javax.net.ssl.SSLParameters",
                WssSslConfigUtil.getSslParameters()
        );
        return wsClient;
    }

    /**
     * 重连指定客户端（连接异常/关闭时自动触发）
     */
    public void reconnect(WsClientConfig config) {
        executor.submit(() -> {
            try {
                // 重连间隔（5秒），避免频繁重试
                Thread.sleep(5000);
                log.info("🔄 [{}] 尝试重新连接Nginx代理WSS...", config.getClientId());
                connect(config);
            } catch (InterruptedException e) {
                log.error("[{}] 重连线程被中断", config.getClientId(), e);
                Thread.currentThread().interrupt();
            }
        });
    }

    /**
     * 绑定客户端ID和会话（供处理器调用）
     */
    public void bindSession(String clientId, WebSocketSession session) {
        sessionMap.put(clientId, session);
    }

    /**
     * 移除指定客户端的会话（供处理器调用）
     */
    public void removeSession(String clientId) {
        sessionMap.remove(clientId);
    }

    /**
     * 项目关闭时优雅释放资源
     */
    @PreDestroy
    public void destroy() {
        // 关闭所有WS会话
        sessionMap.forEach((clientId, session) -> {
            if (session.isOpen()) {
                try {
                    session.close();
                    log.info("🔚 [{}] Nginx代理WSS连接已关闭", clientId);
                } catch (Exception e) {
                    log.error("🔚 [{}] 关闭Nginx代理WSS连接失败", clientId, e);
                }
            }
        });
        // 关闭线程池
        executor.shutdown();
        log.info("🔚 所有Nginx代理WSS客户端资源已释放");
    }
}