package com.ruoyi.web.controller.system;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.system.domain.ControllerData;
import com.ruoyi.system.domain.topics;
import com.ruoyi.system.service.SysControllerService;
import com.ruoyi.system.service.TDengineService;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.net.ssl.*;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;


/**
 * 存储控制器数据
 */
@Service
@Component
@RequestMapping("MessageListenerService3")
public class TdengineController2 {
    private static ExecutorService threadPool= Executors.newCachedThreadPool();
    /**
     *
     * 添加mysql数据
     *
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    public SysControllerService sysControllerService;
    @Autowired
    public TdegnineController3 messageListenerService2;



//    // 核心修正：将tcp://改为ssl://（与mqtts://等价，适配SSL SocketFactory）
//    private static final String BROKER_URL = "ssl://10.168.1.19:8883";
//    // 其他配置保持不变（SSL_BROKER_HOST、SSL_BROKER_PORT等无需修改）
//    private static final String SSL_BROKER_HOST = "10.168.1.19";
//    private static final int SSL_BROKER_PORT = 8883;
//    private static final int QOS = 1;
//    private static final String SUBSCRIBE_TOPIC = "+/generics";
//    private static final int CONNECT_TIMEOUT = 3000;
//    private static final int RECONNECT_INTERVAL = 5000;
//    private static final String CA_CERT_PATH = "ca.crt"; // 已修正的证书路径
//    // ======================================================================================
//
//    // 你的其他成员变量保持不变 ↓
//    @Autowired
//    public TDengineService tDengineMapceshi2;
//    private MqttClient mqttClient;
//    private final ExecutorService executorService = Executors.newSingleThreadExecutor();
//    private boolean isMqttConnected = false;
//    private MqttConnectOptions connOpts;
//    private ObjectMapper objectMapper = new ObjectMapper();
//
//    @PostConstruct
//    public void connectAndSubscribe() {
//        try {
//            // 1. 检测SSL MQTT服务器连通性（保持不变）
//            checkServerAvailability();
//            // 2. 创建MQTT客户端（保持不变，使用修改后的tcp://地址）
//            String clientId = generateClientIdByOs();
//            mqttClient = new MqttClient(BROKER_URL, clientId, new MemoryPersistence());
//            // 3. 初始化MQTT连接选项
//            initMqttConnectOptions();
//            // 4. 设置MQTT回调（保持不变）
//            setMqttCallback();
//            // 5. 建立连接并订阅主题（保持不变）
//            connectAndSubscribeTopic();
//        } catch (MqttException | InterruptedException e) {
//            System.err.println("MQTT SSL客户端初始化失败：" + e.getMessage());
//            e.printStackTrace();
//        }
//    }
//
//    /**
//     * 新增核心方法：手动注册mqtts协议对应的SslNetworkModule
//     * 解决Paho 1.2.5版本 "no NetworkModule installed for scheme mqtts" 异常
//     */
//    private void checkServerAvailability() throws InterruptedException {
//        // 你的原有代码，无需改动
//        boolean serverAvailable = false;
//        while (!serverAvailable) {
//            try (Socket socket = new Socket()) {
//                socket.connect(new InetSocketAddress(SSL_BROKER_HOST, SSL_BROKER_PORT), CONNECT_TIMEOUT);
//                serverAvailable = true;
//                System.out.println("SSL MQTT服务器连通性检测通过");
//            } catch (Exception e) {
//                System.err.println("SSL MQTT服务器不可达，5秒后重试...");
//                Thread.sleep(RECONNECT_INTERVAL);
//            }
//        }
//    }
//
//    /**
//     * 初始化MQTT连接选项
//     */
//    private void initMqttConnectOptions() {
//        connOpts = new MqttConnectOptions();
//        connOpts.setCleanSession(true);
//        connOpts.setAutomaticReconnect(true);
//        connOpts.setConnectionTimeout(10);
//        // 你的原有SSL配置（已包含SSL Socket工厂设置，这是核心）
//        configureSslAndStrictHostnameVerify();
//    }
//    /**
//     * 按操作系统生成唯一ClientId
//     */
//    private String generateClientIdByOs() {
//        String osName = System.getProperty("os.name").toLowerCase();
//        return osName.contains("windows") ? "mqttx_e216fbf1615" : "mqttx_e216fbf1616";
//    }
//    /**
//     * 配置SSL（加载CA证书，严格验证证书有效性） + 严格主机名验证（匹配CN/SAN）
//     */
//    private void configureSslAndStrictHostnameVerify() {
//        try {
//            // 1. 加载CA根证书（从resources目录读取，ClassPathResource自动识别根目录）
//            CertificateFactory cf = CertificateFactory.getInstance("X.509");
//            ClassPathResource caResource = new ClassPathResource(CA_CERT_PATH);
//            X509Certificate caCert;
//            try (InputStream caIn = caResource.getInputStream()) {
//                caCert = (X509Certificate) cf.generateCertificate(caIn);
//            }
//
//            // 2. 创建信任库，并导入CA证书（替代"信任所有证书"，生产环境必用）
//            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
//            trustStore.load(null, null); // 初始化空信任库
//            trustStore.setCertificateEntry("mqtt_ca_cert", caCert); // 导入CA证书
//
//            // 3. 创建信任管理器工厂（严格验证服务端证书）
//            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//            tmf.init(trustStore);
//
//            // 4. 初始化SSL上下文
//            SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); // 推荐TLSv1.2/1.3
//            sslContext.init(null, tmf.getTrustManagers(), new java.security.SecureRandom());
//            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
//
//            // 5. 设置SSL Socket工厂到MQTT连接选项
//            connOpts.setSocketFactory(sslSocketFactory);
//
//            // 6. 严格主机名验证（核心：匹配证书的CN或SAN）
//            setStrictHostnameVerifier();
//
//        } catch (Exception e) {
//            System.err.println("SSL配置 + 主机名验证初始化失败：" + e.getMessage());
//            e.printStackTrace();
//        }
//    }
//    /**
//     * 严格主机名验证：验证服务器主机名/IP 是否与证书的CN（通用名称）或SAN（备用名称）一致
//     * 生产环境必用，防止主机名欺骗攻击
//     */
//    private void setStrictHostnameVerifier() {
//        connOpts.setSSLHostnameVerifier(new HostnameVerifier() {
//            @Override
//            public boolean verify(String hostname, SSLSession session) {
//                try {
//                    // 步骤1：获取服务端返回的证书链（第一个为服务端证书）
//                    X509Certificate[] certChain = (X509Certificate[]) session.getPeerCertificates();
//                    X509Certificate serverCert = certChain[0]; // 服务端核心证书
//
//                    // 步骤2：先验证证书的CN（通用名称）
//                    String certCN = getCNFromX509Certificate(serverCert);
//                    if (certCN != null && hostname.equals(certCN)) {
//                        System.out.println("主机名验证通过（匹配证书CN：" + certCN + "）");
//                        return true;
//                    }
//
//                    // 步骤3：若CN不匹配，验证SAN（备用名称，支持多域名/IP，推荐优先验证SAN）
//                    boolean sanMatched = verifySANFromX509Certificate(serverCert, hostname);
//                    if (sanMatched) {
//                        System.out.println("主机名验证通过（匹配证书SAN：" + hostname + "）");
//                        return true;
//                    }
//
//                    // 步骤4：CN和SAN均不匹配，验证失败
//                    System.err.println("主机名验证失败！期望：" + hostname + "，证书CN：" + certCN + "，证书SAN不包含该主机名");
//                    return false;
//
//                } catch (Exception e) {
//                    System.err.println("主机名验证异常：" + e.getMessage());
//                    e.printStackTrace();
//                    return false;
//                }
//            }
//        });
//    }
//
//    /**
//     * 从X509证书中提取CN（通用名称）
//     * 格式示例：SubjectDN = "C=CN, ST=Beijing, L=Beijing, O=Test, CN=10.168.1.19"
//     */
//    private String getCNFromX509Certificate(X509Certificate cert) {
//        String subjectDN = cert.getSubjectDN().getName();
//        // 分割SubjectDN，遍历获取CN=开头的字段
//        String[] dnParts = subjectDN.split(",");
//        for (String part : dnParts) {
//            String trimmedPart = part.trim();
//            if (trimmedPart.startsWith("CN=")) {
//                return trimmedPart.substring(3); // 截取CN=后面的内容
//            }
//        }
//        return null;
//    }
//
//    /**
//     * 验证证书的SAN（备用名称）是否包含目标主机名
//     * SAN类型：2=DNS域名，7=IP地址
//     */
//    private boolean verifySANFromX509Certificate(X509Certificate cert, String targetHostname) {
//        try {
//            // 获取SAN扩展字段
//            Collection<List<?>> sanExtensions = cert.getSubjectAlternativeNames();
//            if (sanExtensions == null || sanExtensions.isEmpty()) {
//                return false;
//            }
//
//            // 遍历SAN字段，匹配目标主机名
//            for (List<?> sanItem : sanExtensions) {
//                if (sanItem.size() < 2) {
//                    continue;
//                }
//                Integer sanType = (Integer) sanItem.get(0);
//                String sanValue = (String) sanItem.get(1);
//
//                // 匹配DNS类型（2）或IP类型（7）的SAN
//                if ((sanType == 2 || sanType == 7) && targetHostname.equals(sanValue)) {
//                    return true;
//                }
//            }
//            return false;
//        } catch (Exception e) {
//            System.err.println("提取证书SAN异常：" + e.getMessage());
//            return false;
//        }
//    }
//
//    /**
//     * 设置MQTT回调函数
//     */
//    private void setMqttCallback() {
//        mqttClient.setCallback(new MqttCallback() {
//            @Override
//            public void connectionLost(Throwable cause) {
//                System.err.println("MQTT连接断开，开始重连：" + cause.getMessage());
//                isMqttConnected = false;
//                reconnect();
//            }
//
//            @Override
//            public void messageArrived(String topic, MqttMessage message) throws Exception {
//                if (isMqttConnected) {
//                    executorService.submit(() -> {
//                        try {
//                                String mqtt = message.toString();
//                                ObjectMapper objectMapper = new ObjectMapper();
//                            // 正确读取消息负载
//                            String messageContent = new String(message.getPayload(), "UTF-8");
//                            ControllerData listOfMaps = objectMapper.readValue(mqtt, ControllerData.class);
//
//                            // 业务处理
//                            chufafangfa(listOfMaps);
////                            processMessage(messageContent);
//                        } catch (Exception e) {
//                            System.err.println("消息处理失败：" + e.getMessage());
//                            e.printStackTrace();
//                        }
//                    });
//                }
//            }
//
//            @Override
//            public void deliveryComplete(IMqttDeliveryToken token) {
//                // 消息投递完成回调（无需处理）
//            }
//        });
//    }
//
//    /**
//     * 建立MQTT连接并订阅主题
//     */
//    private void connectAndSubscribeTopic() throws MqttException {
//        if (!mqttClient.isConnected()) {
//            IMqttToken connectToken = mqttClient.connectWithResult(connOpts);
//            if (connectToken.isComplete()) {
//                mqttClient.subscribe(SUBSCRIBE_TOPIC, QOS);
//                isMqttConnected = true;
//                System.out.println("MQTT SSL连接成功，已订阅主题：" + SUBSCRIBE_TOPIC);
//            }
//        }
//    }
//
//    /**
//     * MQTT重连逻辑
//     */
//    public void reconnect() {
//        int maxReconnectAttempts = 3;
//        for (int attempt = 1; attempt <= maxReconnectAttempts; attempt++) {
//            try {
//                Thread.sleep(RECONNECT_INTERVAL);
//                if (mqttClient != null && !mqttClient.isConnected()) {
//                    mqttClient.connect(connOpts);
//                    mqttClient.subscribe(SUBSCRIBE_TOPIC, QOS);
//                    isMqttConnected = true;
//                    System.out.println("MQTT SSL重连成功（第" + attempt + "次尝试）");
//                    break; // 重连成功后退出循环
//                }
//            } catch (MqttException | InterruptedException e) {
//                System.err.println("MQTT SSL重连失败（第" + attempt + "次尝试）：" + e.getMessage());
//                if (attempt == maxReconnectAttempts) {
//                    System.err.println("已达最大重连次数，停止重连");
//                }
//            }
//        }
//    }
//
//
////    // 业务方法：处理MQTT消息
////    private void processMessage(String messageContent) {
////        // 你的业务逻辑实现
////    }
//
//    /**
//     * 销毁时断开MQTT连接，关闭线程池
//     */
//    @PreDestroy
//    public void disconnect() {
//        try {
//            if (mqttClient != null && mqttClient.isConnected()) {
//                mqttClient.disconnect();
//                mqttClient.close();
//                System.out.println("MQTT SSL连接已断开");
//            }
//            executorService.shutdown();
//            threadPool.shutdown();
//        } catch (MqttException e) {
//            System.err.println("MQTT SSL断开连接失败：" + e.getMessage());
//            e.printStackTrace();
//        }
//    }

    // ========== 移除SSL，改用普通TCP连接 ==========
    // 普通MQTT协议（tcp://，等价于mqtt://），默认端口1883，可根据服务端修改
    private static final String BROKER_URL = "tcp://47.104.204.180:1883";
    // 普通MQTT服务端地址（移除SSL前缀）
    private static final String BROKER_HOST = "47.104.204.180";
    // 普通MQTT服务端端口（移除SSL端口8883，改用默认1883，可根据服务端修改）
    private static final int BROKER_PORT = 1883;

    private static final int QOS = 1;
    // 保留原有订阅主题
    private static final String SUBSCRIBE_TOPIC = "+/generics";
    private static final int CONNECT_TIMEOUT = 3000;
    private static final int RECONNECT_INTERVAL = 5000;

    // ========== 新增：MQTT账号密码（替换为你的服务端实际配置） ==========
    private static final String MQTT_USERNAME = "NjniyrEO"; // 实际用户名
    private static final String MQTT_PASSWORD = "2b577892f4824d466dbc323a1ee4dfe1902c55bb"; // 实际密码

    // 移除：SSL相关的CA_CERT_PATH常量（无需证书配置）
    // 你的其他成员变量保持不变
    @Autowired
    public TDengineService tDengineMapceshi2;
    private MqttClient mqttClient;
    private final ExecutorService executorService = Executors.newSingleThreadExecutor();
    private boolean isMqttConnected = false;
    private MqttConnectOptions connOpts;
    private ObjectMapper objectMapper = new ObjectMapper();


    // 移除：未定义的threadPool引用（避免编译错误）
    @PostConstruct
    public void connectAndSubscribe() {
        try {
            // 1. 检测普通MQTT服务器连通性（移除SSL，仅检测TCP端口）
            checkServerAvailability();
            // 2. 创建MQTT客户端（使用普通TCP的BROKER_URL，保持逻辑不变）
            String clientId = generateClientIdByOs();
            mqttClient = new MqttClient(BROKER_URL, clientId, new MemoryPersistence());
            // 3. 初始化MQTT连接选项（移除SSL配置，新增账号密码）
            initMqttConnectOptions();
            // 4. 设置MQTT回调（保持核心逻辑，修复消息解析bug）
            setMqttCallback();
            // 5. 建立连接并订阅主题（保持逻辑不变，移除SSL日志标识）
            connectAndSubscribeTopic();
        } catch (MqttException | InterruptedException e) {
            System.err.println("MQTT客户端初始化失败：" + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 检测普通MQTT服务器连通性（移除SSL，仅验证TCP端口可达性）
     */
    private void checkServerAvailability() throws InterruptedException {
        boolean serverAvailable = false;
        while (!serverAvailable) {
            try (Socket socket = new Socket()) {
                // 改用普通BROKER_HOST和BROKER_PORT
                socket.connect(new InetSocketAddress(BROKER_HOST, BROKER_PORT), CONNECT_TIMEOUT);
                serverAvailable = true;
                System.out.println("普通MQTT服务器连通性检测通过");
            } catch (Exception e) {
                System.err.println("普通MQTT服务器不可达，5秒后重试...");
                Thread.sleep(RECONNECT_INTERVAL);
            }
        }
    }

    /**
     * 初始化MQTT连接选项（移除SSL配置，新增账号密码认证）
     */
    private void initMqttConnectOptions() {
        connOpts = new MqttConnectOptions();
        connOpts.setCleanSession(true);
        connOpts.setAutomaticReconnect(true);
        connOpts.setConnectionTimeout(10);

        // ========== 新增：配置MQTT账号密码 ==========
        connOpts.setUserName(MQTT_USERNAME);
        connOpts.setPassword(MQTT_PASSWORD.toCharArray()); // 密码要求传入char数组

        // 移除：原有的SSL配置方法调用（configureSslAndStrictHostnameVerify()）
    }

    /**
     * 按操作系统生成唯一ClientId（保持原有逻辑不变）
     */
    private String generateClientIdByOs() {
        String osName = System.getProperty("os.name").toLowerCase();
        return osName.contains("windows") ? "mqttx_e216fbf1615" : "mqttx_e216fbf1616";
    }

    /**
     * 设置MQTT回调函数（保留核心逻辑，修复2个关键bug）
     */
    private void setMqttCallback() {
        mqttClient.setCallback(new MqttCallback() {
            @Override
            public void connectionLost(Throwable cause) {
                System.err.println("MQTT连接断开，开始重连：" + cause.getMessage());
                isMqttConnected = false;
                reconnect();
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                if (isMqttConnected) {
                    executorService.submit(() -> {
                        try {
                            ObjectMapper objectMapper = new ObjectMapper();
                            // 修复bug1：原代码先读取正确的messageContent，却误用mqtt（message.toString()）解析
                            // 正确读取消息负载（UTF-8编码，避免乱码）
                            String messageContent = new String(message.getPayload(), "UTF-8");
                            // 修复bug2：用正确的messageContent解析为ControllerData对象
                            ControllerData controllerData = objectMapper.readValue(messageContent, ControllerData.class);
                            // 业务处理
                            triggermethod(controllerData);
                        } catch (Exception e) {
                            System.err.println("消息处理失败：" + e.getMessage());
                            e.printStackTrace();
                        }
                    });
                }
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
                // 消息投递完成回调（无需处理）
            }
        });
    }

    /**
     * 建立MQTT连接并订阅主题（保持逻辑不变，移除SSL日志标识）
     */
    private void connectAndSubscribeTopic() throws MqttException {
        if (!mqttClient.isConnected()) {
            IMqttToken connectToken = mqttClient.connectWithResult(connOpts);
            if (connectToken.isComplete()) {
                mqttClient.subscribe(SUBSCRIBE_TOPIC, QOS);
                isMqttConnected = true;
                System.out.println("MQTT连接成功，已订阅主题：" + SUBSCRIBE_TOPIC);
            }
        }
    }

    /**
     * MQTT重连逻辑（移除SSL日志标识，保持功能不变）
     */
    public void reconnect() {
        int maxReconnectAttempts = 3;
        for (int attempt = 1; attempt <= maxReconnectAttempts; attempt++) {
            try {
                Thread.sleep(RECONNECT_INTERVAL);
                if (mqttClient != null && !mqttClient.isConnected()) {
                    mqttClient.connect(connOpts);
                    mqttClient.subscribe(SUBSCRIBE_TOPIC, QOS);
                    isMqttConnected = true;
                    System.out.println("MQTT重连成功（第" + attempt + "次尝试）");
                    break; // 重连成功后退出循环
                }
            } catch (MqttException | InterruptedException e) {
                System.err.println("MQTT重连失败（第" + attempt + "次尝试）：" + e.getMessage());
                if (attempt == maxReconnectAttempts) {
                    System.err.println("已达最大重连次数，停止重连");
                }
            }
        }
    }

    /**
     * 销毁时断开MQTT连接，关闭线程池（移除未定义的threadPool.shutdown()）
     */
    @PreDestroy
    public void disconnect() {
        try {
            if (mqttClient != null && mqttClient.isConnected()) {
                mqttClient.disconnect();
                mqttClient.close();
                System.out.println("MQTT连接已断开");
            }
            executorService.shutdown();
            // 移除：原代码中未定义的threadPool.shutdown();（避免编译错误）
        } catch (MqttException e) {
            System.err.println("MQTT断开连接失败：" + e.getMessage());
            e.printStackTrace();
        }
    }



    public void triggermethod(ControllerData weather) throws Exception {
        String timestamp = weather.getTimestamp();
        String fleetId = weather.getFleet_id();
        String controllerId = weather.getController_id();
        List<topics> topics = weather.getTopics();
        List<topics> cmdtopics = weather.getCmd_topics();
        topics faultprot = weather.getFault_prot();
        //需要检索全部的数据是否存在，如果存储就进行修改，如果不存在就进行添加
        Integer controllercountcount=0;
        for (topics topicsMap : topics) {
            Integer count = sysControllerService.selectsyscontrollercount(topicsMap.getPath());
            if (count <= 0) {
                stringRedisTemplate.persist(controllerId);
                stringRedisTemplate.opsForHash().put(controllerId+":"+topicsMap.getName(), "path", topicsMap.getPath());
                //将数据存储到redis
                sysControllerService.insertsyscontroller(controllerId, timestamp, fleetId, topicsMap.getName(), topicsMap.getPath());
                controllercountcount++;
            }
        }
        Integer controllercountcmdcount=0;
        for (topics cmdtopicsMap : cmdtopics) {
            //将数据存储到redis
            Integer count = sysControllerService.selectsyscontrollercountcmd(cmdtopicsMap.getPath());
            if (count<=0) {
                stringRedisTemplate.opsForHash().put(controllerId+"_cmd:"+cmdtopicsMap.getName(), "path", cmdtopicsMap.getPath());
                stringRedisTemplate.persist(controllerId);
                sysControllerService.insertsyscontrollercmd(controllerId, timestamp, fleetId, cmdtopicsMap.getName(), cmdtopicsMap.getPath());
                controllercountcmdcount++;
            }
        }
        Integer count =sysControllerService.selectsyscontrollercountfault(faultprot.getPath());
        if (count<=0){
            stringRedisTemplate.opsForHash().put(controllerId+"_fault:"+faultprot.getName(), "path", faultprot.getPath());
            sysControllerService.insertsyscontrollerfault(controllerId, timestamp, fleetId, faultprot.getName(), faultprot.getPath());
            stringRedisTemplate.persist(controllerId);
        }
        //如果控制器中的数据出现更新情况，就触发该方法进行重连
        if (controllercountcount>0) {
            //关闭连接线程
            messageListenerService2.destroy();
            //重新建立连接
            messageListenerService2.initMqttConnection();
        }
    }

//    @PreDestroy
//    public void destroyMqttConnection() {
//        synchronized (lock) {
//            // 断开MQTT连接
//            disconnect();
//
//            // 关闭线程池
//            shutdownExecutorService(reconnectExecutor);
//            shutdownExecutorService(messageExecutor);
//        }
//    }

}
