package com.data.emqx;

/**
 * @author licd
 * @className MqttDeviceClient
 * @description 集疏运终端设备MQTT协议接收客户端
 * @date 2026/03/17
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.data.emqx.service.IDeviceDataService;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
public class MqttDeviceClient {

    private static final Logger logger = LoggerFactory.getLogger(MqttDeviceClient.class);

    // Broker配置
    @Value("${device.mqtt.broker:tcp://127.0.0.1:1883}")
    private String broker;

    @Value("${device.mqtt.username:emqx_public}")
    private String username;

    @Value("${device.mqtt.password:emqx_public}")
    private String password;

    @Value("${device.mqtt.clientId:server_client_001}")
    private String clientId;

    // V2.0.1 Topic配置 - 动态层级结构
    // 设备端发布(上行): WgtRfid/device/${did}
    // 服务器下发(下行): WgtRfid/server/${did}
    private static final String TOPIC_DEVICE_UPLINK = "WgtRfid/device/#";
    private static final String TOPIC_SERVER_DOWNLINK_PREFIX = "WgtRfid/server/";
    
    // 兼容旧版 Topic（V1.0.1）
    private static final String TOPIC_RFID_WGT = "Topic_RFID_WGT";
    private static final String TOPIC_HEART = "Topic_Heart";
    private static final String TOPIC_ALARM = "Topic_ALARM";

    // V2.0.1 QoS配置 - 统一为QoS 0
    private static final int QOS = 0;

    // V2.0.1 消息类型
    private static final String MSG_TYPE_WEIGHT_RFID = "weight_rfid";
    private static final String MSG_TYPE_ALARM = "alarm";
    private static final String MSG_TYPE_HEART = "heart";
    private static final String MSG_TYPE_OTA_PROGRESS = "ota_progress";
    private static final String MSG_TYPE_PARAM_READ = "param_read";
    private static final String MSG_TYPE_PARAM_WRITE = "param_write";

    private MqttClient mqttClient;
    
    // 异步ACK发送线程池（避免在messageArrived回调中直接调用publish导致死锁）
    private final ExecutorService ackSenderExecutor = Executors.newFixedThreadPool(2);

    @Autowired
    private IDeviceDataService deviceDataService;

    /**
     * 初始化MQTT客户端连接
     */
    @PostConstruct
    public void init() {
        // 测试数据保存功能
//        testDataSave();
        connect();

    }

    /**
     * 测试数据保存功能
     */
    private void testDataSave() {
        try {
            logger.info("=== 开始测试数据保存功能 ===");

            // 测试保存称重&标签数据
            if (deviceDataService != null) {
                String deviceId = "test_device_001";
                Long seqNum = 123456789L;
                Long sendTime = System.currentTimeMillis() / 1000;
                Integer weight = 1000;
                String rfid = "e280111122223333,b001111122223333";

                deviceDataService.saveWeightRfidData(deviceId, seqNum, sendTime, weight, rfid);
                logger.info("称重&标签数据保存测试成功");

                // 测试保存告警数据
                Long alarmSeqNum = 987654321L;
                String uwb = "ID:1234,dist:2000; ID:5678,dist:1500";
                com.alibaba.fastjson.JSONArray uwbArray = new com.alibaba.fastjson.JSONArray();
                com.alibaba.fastjson.JSONObject uwbObj1 = new com.alibaba.fastjson.JSONObject();
                uwbObj1.put("ID", "1234");
                uwbObj1.put("Dist", "2000 cm");
                uwbArray.add(uwbObj1);
                com.alibaba.fastjson.JSONObject uwbObj2 = new com.alibaba.fastjson.JSONObject();
                uwbObj2.put("ID", "5678");
                uwbObj2.put("Dist", "1500 cm");
                uwbArray.add(uwbObj2);

                deviceDataService.saveAlarmData(deviceId, alarmSeqNum, sendTime, uwb, uwbArray);
                logger.info("告警数据保存测试成功");

                // 测试保存心跳数据
                Double sysVol = 12.8;
                Integer netRSSI = -75;

                deviceDataService.saveHeartData(deviceId, sysVol, netRSSI, sendTime);
                logger.info("心跳数据保存测试成功");

                // V2.0.1 测试保存OTA升级进度数据
                String taskID = "ota_task_001";
                Integer progress = 50;
                String otaStatus = "InProgress";
                deviceDataService.saveOtaProgressData(deviceId, taskID, progress, otaStatus);
                logger.info("OTA升级进度数据保存测试成功");

                // V2.0.1 测试保存设备参数写入响应
                Long paramSeqNum = 111222333L;
                String paramStatus = "OK";
                String failReason = null;
                deviceDataService.saveParamWriteData(deviceId, paramSeqNum, paramStatus, failReason);
                logger.info("设备参数写入响应保存测试成功");

                // V2.0.1 测试保存设备参数期望值（用于设备上线后自动拉平配置）
                // 需要通过 DeviceDataServiceImpl 直接调用
                if (deviceDataService instanceof com.data.emqx.service.impl.DeviceDataServiceImpl) {
                    com.data.emqx.service.impl.DeviceDataServiceImpl impl =
                            (com.data.emqx.service.impl.DeviceDataServiceImpl) deviceDataService;

                    // 保存几个设备参数期望值
                    impl.saveParamExpectation(deviceId, "Rs485_PollMs", "1000");
                    impl.saveParamExpectation(deviceId, "UWB_AlarmMs", "5000");
                    impl.saveParamExpectation(deviceId, "VoiceAlarmMs", "3000");
                    impl.saveParamExpectation(deviceId, "UWB_IgnoreCm", "50");
                    impl.saveParamExpectation(deviceId, "UWB_AlarmCm", "200");
                    logger.info("设备参数期望值保存测试成功");
                }

            } else {
                logger.error("deviceDataService 为 null，无法测试数据保存功能");
            }

            logger.info("=== 数据保存功能测试完成 ===");

            // V2.0.1 测试设备上线参数同步功能
            testDeviceParamSync("test_device_001");
        } catch (Exception e) {
            logger.error("测试数据保存功能异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 连接MQTT服务器
     */
    public void connect() {
        try {
            // 创建MQTT客户端
            mqttClient = new MqttClient(broker, clientId, new MemoryPersistence());

            // 配置连接选项
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setUserName(username);
            connOpts.setPassword(password.toCharArray());
            connOpts.setCleanSession(true);
            connOpts.setAutomaticReconnect(true);
            connOpts.setConnectionTimeout(30);
            connOpts.setKeepAliveInterval(60);
            connOpts.setMaxInflight(100);

            // 设置断线重连回调
            mqttClient.setCallback(new MqttCallbackExtended() {
                @Override
                public void connectComplete(boolean reconnect, String serverURI) {
                    if (reconnect) {
                        logger.info("MQTT连接已自动重连到: {}", serverURI);
                        subscribeTopics();
                    } else {
                        logger.info("MQTT连接已建立: {}", serverURI);
                    }
                }

                @Override
                public void connectionLost(Throwable cause) {
                    logger.error("MQTT连接断开: {}", cause.getMessage(), cause);
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) {
                    processMessage(topic, message);
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    logger.debug("消息发送完成");
                }
            });

            // 建立连接
            logger.info("正在连接MQTT Broker: {}", broker);
            mqttClient.connect(connOpts);

            // 订阅Topic
            subscribeTopics();

            logger.info("MQTT客户端初始化完成");

        } catch (MqttException e) {
            logger.error("MQTT连接失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 订阅Topic（V2.0.1 动态层级结构）
     * 设备端发布到: WgtRfid/device/${did}
     */
    private void subscribeTopics() {
        try {
            // V2.0.1 使用通配符订阅所有设备的动态Topic
            IMqttToken token = mqttClient.subscribeWithResponse(TOPIC_DEVICE_UPLINK, QOS);
            token.waitForCompletion();
            if (token.isComplete()) {
                logger.info("订阅成功 - Topic: {}, QoS: {} (V2.0.1动态Topic)", TOPIC_DEVICE_UPLINK, QOS);
            } else {
                logger.error("订阅失败 - Topic: {}", TOPIC_DEVICE_UPLINK);
            }
            
            // 兼容旧版 Topic（V1.0.1）
            subscribeTopic(TOPIC_RFID_WGT);
            subscribeTopic(TOPIC_HEART);
            subscribeTopic(TOPIC_ALARM);

        } catch (MqttException e) {
            logger.error("订阅Topic异常: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 订阅单个Topic
     */
    private void subscribeTopic(String topic) {
        try {
            IMqttToken token = mqttClient.subscribeWithResponse(topic, QOS);
            token.waitForCompletion();
            if (token.isComplete()) {
                logger.info("订阅成功 - Topic: {}, QoS: {} (旧版兼容)", topic, QOS);
            } else {
                logger.error("订阅失败 - Topic: {}", topic);
            }
        } catch (MqttException e) {
            logger.error("订阅Topic异常: {}, Error: {}", topic, e.getMessage());
        }
    }

    /**
     * 处理接收到的消息（兼容V1.0.1和V2.0.1）
     * V2.0.1 Topic格式: WgtRfid/device/${did} - deviceId从Topic路径提取
     * V1.0.1 Topic格式: Topic_RFID_WGT/Topic_HEART/Topic_ALARM - deviceId从JSON提取
     */
    private void processMessage(String topic, MqttMessage message) {
        // 调试：确认消息被接收
        String debugMsg = "===== processMessage 方法被调用 ===== Topic: " + topic + ", QoS: " + message.getQos();
        logger.info(debugMsg);
        System.out.println(debugMsg);

        String payload = new String(message.getPayload());
        logger.info("收到消息 - Topic: {}, Payload: {}", topic, payload);

        try {
            // 解析JSON（先解析，因为旧版需要从JSON提取deviceId）
            JSONObject jsonObject = JSON.parseObject(payload);
            
            // V2.0.1: deviceId从Topic路径提取
            // V1.0.1: deviceId从JSON提取（兼容旧版）
            String deviceId = extractDeviceIdFromTopic(topic);
            boolean isOldProtocol = false;
            
            // 如果从Topic无法提取deviceId，尝试从JSON提取（旧版兼容）
            if (deviceId == null || deviceId.isEmpty()) {
                deviceId = jsonObject.getString("deviceID");
                isOldProtocol = true;
            }

            // 调试：显示提取的deviceId
            String deviceIdMsg = "从" + (isOldProtocol ? "JSON" : "Topic") + "提取的DeviceID: " + (deviceId != null ? deviceId : "null") + " (协议版本: " + (isOldProtocol ? "V1.0.1" : "V2.0.1") + ")";
            logger.info(deviceIdMsg);
            System.out.println(deviceIdMsg);

            if (deviceId == null || deviceId.isEmpty()) {
                logger.error("无法从Topic或JSON提取deviceId: {}", topic);
                return;
            }

            // 获取消息类型
            String messageType = jsonObject.getString("messageType");
            
            // 旧版兼容：如果没有messageType字段，根据Topic推断消息类型
            if (messageType == null || messageType.isEmpty()) {
                messageType = inferMessageTypeFromTopic(topic);
            }

            if (messageType == null) {
                logger.error("消息缺少必要字段: messageType");
                return;
            }

            // 根据messageType处理不同类型的消息（传递协议版本）
            switch (messageType) {
                case MSG_TYPE_WEIGHT_RFID:
                    processWeightRfidData(deviceId, jsonObject, isOldProtocol);
                    break;
                case MSG_TYPE_ALARM:
                    processAlarmData(deviceId, jsonObject, isOldProtocol);
                    break;
                case MSG_TYPE_HEART:
                    processHeartData(deviceId, jsonObject);
                    break;
                case MSG_TYPE_OTA_PROGRESS:
                    processOtaProgressData(deviceId, jsonObject);
                    break;
                case MSG_TYPE_PARAM_READ:
                    processParamReadData(deviceId, jsonObject);
                    break;
                case MSG_TYPE_PARAM_WRITE:
                    processParamWriteData(deviceId, jsonObject);
                    break;
                default:
                    logger.warn("未知的消息类型: {}", messageType);
            }

        } catch (Exception e) {
            logger.error("消息处理异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 从Topic路径提取deviceId
     * V2.0.1 Topic格式: WgtRfid/device/${did}
     */
    private String extractDeviceIdFromTopic(String topic) {
        if (topic == null || topic.isEmpty()) {
            return null;
        }
        String prefix = "WgtRfid/device/";
        if (topic.startsWith(prefix)) {
            return topic.substring(prefix.length());
        }
        return null;
    }
    
    /**
     * 从Topic推断消息类型（旧版兼容）
     * V1.0.1 的Topic直接表示消息类型
     */
    private String inferMessageTypeFromTopic(String topic) {
        if (topic == null || topic.isEmpty()) {
            return null;
        }
        switch (topic) {
            case TOPIC_RFID_WGT:
                return MSG_TYPE_WEIGHT_RFID;
            case TOPIC_HEART:
                return MSG_TYPE_HEART;
            case TOPIC_ALARM:
                return MSG_TYPE_ALARM;
            default:
                return null;
        }
    }

    /**
     * 处理称重&标签数据
     */
    private void processWeightRfidData(String deviceId, JSONObject jsonObject, boolean isOldProtocol) {
        try {
            // 调试：确认方法被调用
            String debugMsg = "===== processWeightRfidData 方法被调用 ===== DeviceID: " + deviceId + ", Payload: " + jsonObject.toJSONString() + ", Protocol: " + (isOldProtocol ? "V1.0.1" : "V2.0.1");
            logger.info(debugMsg);
            System.out.println(debugMsg);

            logger.info("处理称重&标签数据 - DeviceID: {}", deviceId);

            Long seqNum = jsonObject.getLong("seqNum");
            if (seqNum == null) {
                logger.error("非法消息：seqNum 缺失，丢弃消息且不发送ACK。Payload: {}", jsonObject.toJSONString());
                return;
            }

            // 检查是否已存在相同数据
            if (deviceDataService != null && deviceDataService.existsWeightRfidData(deviceId, seqNum)) {
                logger.info("称重数据已存在，直接返回ACK - DeviceID: {}, SeqNum: {}", deviceId, seqNum);
                // 异步发送ACK（避免在messageArrived回调中直接调用publish导致死锁）
                final Long finalSeqNum1 = seqNum;
                final boolean finalIsOldProtocol1 = isOldProtocol;
                ackSenderExecutor.execute(() -> sendAck(deviceId, finalSeqNum1, "weight_rfid", finalIsOldProtocol1));
                return;
            }

            Long sendTime = jsonObject.getLong("sendTime");
            Integer weight = jsonObject.getInteger("weight");
            if (weight == null) {
                logger.warn("警告：weight 字段缺失，使用默认值0。DeviceID: {}", deviceId);
                weight = 0;
            }

            String rfidStr = null;
            JSONArray rfidArray = jsonObject.getJSONArray("RFID");
            if (rfidArray != null && !rfidArray.isEmpty()) {
                List<String> rfidList = rfidArray.toJavaList(String.class);
                rfidStr = String.join(",", rfidList);
            } else {
                rfidStr = "";
            }

            logger.info("称重数据 - SeqNum: {}, Weight: {}, RFID: {}", seqNum, weight, rfidStr);

            if (deviceDataService != null) {
                deviceDataService.saveWeightRfidData(deviceId, seqNum, sendTime, weight, rfidStr);
            }

            // 异步发送ACK（避免在messageArrived回调中直接调用publish导致死锁）
            final Long finalSeqNum2 = seqNum;
            final boolean finalIsOldProtocol2 = isOldProtocol;
            ackSenderExecutor.execute(() -> sendAck(deviceId, finalSeqNum2, "weight_rfid", finalIsOldProtocol2));

        } catch (Exception e) {
            logger.error("处理称重&标签数据异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 处理告警数据
     */
    private void processAlarmData(String deviceId, JSONObject jsonObject, boolean isOldProtocol) {
        try {
            logger.info("处理告警数据 - DeviceID: {}", deviceId);

            Long seqNum = jsonObject.getLong("seqNum");
            if (seqNum == null) {
                logger.error("非法消息：seqNum 缺失，丢弃消息且不发送ACK。Payload: {}", jsonObject.toJSONString());
                return;
            }

            // 检查是否已存在相同数据
            if (deviceDataService != null && deviceDataService.existsAlarmData(deviceId, seqNum)) {
                logger.info("告警数据已存在，直接返回ACK - DeviceID: {}, SeqNum: {}", deviceId, seqNum);
                // 异步发送ACK（避免在messageArrived回调中直接调用publish导致死锁）
                final Long finalSeqNum3 = seqNum;
                final boolean finalIsOldProtocol3 = isOldProtocol;
                ackSenderExecutor.execute(() -> sendAck(deviceId, finalSeqNum3, "alarm", finalIsOldProtocol3));
                return;
            }

            Long sendTime = jsonObject.getLong("sendTime");

            StringBuilder uwbInfo = new StringBuilder();
            JSONArray uwbArray = jsonObject.getJSONArray("UWB");
            if (uwbArray != null && !uwbArray.isEmpty()) {
                for (int i = 0; i < uwbArray.size(); i++) {
                    JSONObject uwbObj = uwbArray.getJSONObject(i);
                    if (uwbObj == null) continue;

                    Integer id = uwbObj.getInteger("ID");
                    Integer dist = uwbObj.getInteger("dist");

                    if (id == null || dist == null) {
                        logger.warn("UWB子项数据不完整，跳过该项。Item: {}", uwbObj.toJSONString());
                        continue;
                    }

                    if (uwbInfo.length() > 0) {
                        uwbInfo.append("; ");
                    }
                    uwbInfo.append("ID:").append(id).append(",dist:").append(dist);
                }
            }

            logger.info("告警数据 - SeqNum: {}, SendTime: {}, UWB: {}", seqNum, sendTime, uwbInfo);

            if (deviceDataService != null) {
                deviceDataService.saveAlarmData(deviceId, seqNum, sendTime, uwbInfo.toString(), uwbArray);
            }

            // 异步发送ACK（避免在messageArrived回调中直接调用publish导致死锁）
            final Long finalSeqNum4 = seqNum;
            final boolean finalIsOldProtocol4 = isOldProtocol;
            ackSenderExecutor.execute(() -> sendAck(deviceId, finalSeqNum4, "alarm", finalIsOldProtocol4));

        } catch (Exception e) {
            logger.error("处理告警数据异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 处理心跳数据
     */
    private void processHeartData(String deviceId, JSONObject jsonObject) {
        try {
            logger.info("处理心跳数据 - DeviceID: {}", deviceId);

            Double sysVol = jsonObject.getDouble("sysVol");
            Integer netRSSI = jsonObject.getInteger("netRSSI");
            Long sendTime = jsonObject.getLong("sendTime");

            // 检查是否已存在相同数据
            if (deviceDataService != null && deviceDataService.existsHeartData(deviceId, sendTime)) {
                logger.info("心跳数据已存在，直接返回ACK - DeviceID: {}, SendTime: {}", deviceId, sendTime);
                // 心跳数据没有seqNum，不需要发送ACK
                return;
            }

            logger.info("心跳数据 - sysVol: {}, netRSSI: {}, sendTime: {}",
                    sysVol, netRSSI, sendTime);

            if (deviceDataService != null) {
                deviceDataService.saveHeartData(deviceId, sysVol, netRSSI, sendTime);
            }

        } catch (Exception e) {
            logger.error("处理心跳数据异常: {}", e.getMessage(), e);
        }
    }

    /**
     * V2.0.1 处理OTA升级进度数据
     * 设备上报格式：{"messageType": "ota_progress", "taskID": "xxx", "progress": 0-100, "status": "OK/Fail"}
     */
    private void processOtaProgressData(String deviceId, JSONObject jsonObject) {
        try {
            logger.info("处理OTA升级进度数据 - DeviceID: {}", deviceId);

            String taskID = jsonObject.getString("taskID");
            Integer progress = jsonObject.getInteger("progress");
            String status = jsonObject.getString("status");

            logger.info("OTA进度数据 - DeviceID: {}, TaskID: {}, Progress: {}%, Status: {}",
                    deviceId, taskID, progress, status);

            if (deviceDataService != null) {
                deviceDataService.saveOtaProgressData(deviceId, taskID, progress, status);
            }

        } catch (Exception e) {
            logger.error("处理OTA升级进度数据异常: {}", e.getMessage(), e);
        }
    }

    /**
     * V2.0.1 处理设备参数读取响应数据
     * 设备上报格式：{"messageType": "param_read", "seqNum": xxx, "params": {"Rs485_PollMs": xxx, ...}}
     */
    private void processParamReadData(String deviceId, JSONObject jsonObject) {
        try {
            logger.info("处理设备参数读取响应 - DeviceID: {}", deviceId);

            Long seqNum = jsonObject.getLong("seqNum");
            JSONObject params = jsonObject.getJSONObject("params");

            logger.info("参数读取响应 - DeviceID: {}, SeqNum: {}, Params: {}",
                    deviceId, seqNum, params != null ? params.toJSONString() : "null");

            if (deviceDataService != null && params != null) {
                deviceDataService.saveParamReadData(deviceId, seqNum, params);
            }

            if (seqNum != null) {
                // 异步发送ACK（避免在messageArrived回调中直接调用publish导致死锁）
                final Long finalSeqNum5 = seqNum;
                ackSenderExecutor.execute(() -> sendAck(deviceId, finalSeqNum5, MSG_TYPE_PARAM_READ));
            }

        } catch (Exception e) {
            logger.error("处理设备参数读取响应异常: {}", e.getMessage(), e);
        }
    }

    /**
     * V2.0.1 处理设备参数写入响应数据
     * 设备上报格式：{"messageType": "param_write", "seqNum": xxx, "status": "OK/Fail", "failReason": "xxx"}
     */
    private void processParamWriteData(String deviceId, JSONObject jsonObject) {
        try {
            logger.info("处理设备参数写入响应 - DeviceID: {}", deviceId);

            Long seqNum = jsonObject.getLong("seqNum");
            String status = jsonObject.getString("status");
            String failReason = jsonObject.getString("failReason");

            logger.info("参数写入响应 - DeviceID: {}, SeqNum: {}, Status: {}, FailReason: {}",
                    deviceId, seqNum, status, failReason);

            if (deviceDataService != null) {
                deviceDataService.saveParamWriteData(deviceId, seqNum, status, failReason);
            }

            if (seqNum != null) {
                // 异步发送ACK（避免在messageArrived回调中直接调用publish导致死锁）
                final Long finalSeqNum6 = seqNum;
                ackSenderExecutor.execute(() -> sendAck(deviceId, finalSeqNum6, MSG_TYPE_PARAM_WRITE));
            }

        } catch (Exception e) {
            logger.error("处理设备参数写入响应异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 发送ACK回复（兼容V1.0.1和V2.0.1协议）
     * ACK格式：{"messageType": "xxx", "seqNum": xxx, "ackTime": UTC0时间戳(Uint32)}
     * V2.0.1: 下行Topic格式: WgtRfid/server/${deviceId}
     * V1.0.1: 下行Topic格式: ${deviceId}（直接使用设备ID）
     */
    private void sendAck(String deviceId, Long seqNum, String messageType) {
        // 默认使用V2.0.1协议
        sendAck(deviceId, seqNum, messageType, false);
    }
    
    /**
     * 发送ACK回复（兼容V1.0.1和V2.0.1协议）
     * @param deviceId 设备ID
     * @param seqNum 序列号
     * @param messageType 消息类型
     * @param isOldProtocol 是否为旧版协议（V1.0.1）
     */
    private void sendAck(String deviceId, Long seqNum, String messageType, boolean isOldProtocol) {
        String startMsg = "开始发送ACK - DeviceID: " + deviceId + ", Type: " + messageType + ", SeqNum: " + seqNum + ", Protocol: " + (isOldProtocol ? "V1.0.1" : "V2.0.1");
        logger.info(startMsg);
        System.out.println(startMsg);

        if (seqNum == null) {
            String errorMsg = "尝试发送ACK但seqNum为空，拒绝发送！DeviceID: " + deviceId;
            logger.error(errorMsg);
            System.out.println(errorMsg);
            return;
        }

        if (mqttClient == null) {
            String errorMsg = "MQTT客户端未初始化，无法发送ACK！DeviceID: " + deviceId;
            logger.error(errorMsg);
            System.out.println(errorMsg);
            return;
        }

        if (!mqttClient.isConnected()) {
            String errorMsg = "MQTT客户端未连接，无法发送ACK！DeviceID: " + deviceId;
            logger.error(errorMsg);
            System.out.println(errorMsg);
            return;
        }

        try {
            JSONObject ackJson = new JSONObject();
            ackJson.put("messageType", messageType);
            ackJson.put("seqNum", seqNum);

            long utcSeconds = System.currentTimeMillis() / 1000;
            ackJson.put("ackTime", utcSeconds);

            String ackPayload = ackJson.toJSONString();
            
            // 确定下行Topic
            String downlinkTopic;
            if (isOldProtocol) {
                // V1.0.1: 直接使用deviceId作为Topic
                downlinkTopic = deviceId;
            } else {
                // V2.0.1: 使用动态下行Topic
                downlinkTopic = TOPIC_SERVER_DOWNLINK_PREFIX + deviceId;
            }
            
            String prepareMsg = "准备发送ACK消息 - Topic: " + downlinkTopic + ", Payload: " + ackPayload;
            logger.info(prepareMsg);
            System.out.println(prepareMsg);

            MqttMessage ackMessage = new MqttMessage(ackPayload.getBytes());
            ackMessage.setQos(QOS);
            String createMsg = "ACK消息创建成功 - QoS: " + QOS;
            logger.info(createMsg);
            System.out.println(createMsg);

            mqttClient.publish(downlinkTopic, ackMessage);
            String successMsg = "ACK已成功发送 - DeviceID: " + deviceId + ", Type: " + messageType + ", SeqNum: " + seqNum + ", ackTime: " + utcSeconds + ", Topic: " + downlinkTopic;
            logger.info(successMsg);
            System.out.println(successMsg);

        } catch (MqttException e) {
            String errorMsg = "发送ACK失败 - DeviceID: " + deviceId + ", SeqNum: " + seqNum + ", Error: " + e.getMessage();
            logger.error(errorMsg, e);
            System.out.println(errorMsg);
        } catch (Exception e) {
            String errorMsg = "发送ACK时发生未知异常 - DeviceID: " + deviceId + ", SeqNum: " + seqNum + ", Error: " + e.getMessage();
            logger.error(errorMsg, e);
            System.out.println(errorMsg);
        }
    }

    /**
     * 断开连接
     */
    public void disconnect() {
        try {
            if (mqttClient != null && mqttClient.isConnected()) {
                mqttClient.disconnect();
                mqttClient.close();
                logger.info("MQTT连接已断开");
            }
        } catch (MqttException e) {
            logger.error("断开MQTT连接异常: {}", e.getMessage(), e);
        }
    }

    /**
     * V2.0.1 设备上线参数同步测试方法
     * 模拟设备上线后，服务器查询待同步的参数并发送给设备
     * 这是"设备期望值"功能的核心使用场景
     */
    private void testDeviceParamSync(String deviceId) {
        try {
            logger.info("=== 开始设备上线参数同步测试 ===");
            logger.info("设备ID: {}", deviceId);

            // 查询设备待同步的参数（状态为Pending的参数）
            if (deviceDataService instanceof com.data.emqx.service.impl.DeviceDataServiceImpl) {
                com.data.emqx.service.impl.DeviceDataServiceImpl impl =
                        (com.data.emqx.service.impl.DeviceDataServiceImpl) deviceDataService;

                // 获取 DeviceParamWriteMapper
                // 这里为了测试，我们直接模拟查询待同步参数
                logger.info("查询设备待同步的参数...");

                // 模拟查询结果（实际应该调用 deviceParamWriteMapper.selectPendingParamsByDeviceId）
                // 这里打印一些测试信息
                logger.info("设备 {} 的待同步参数列表:", deviceId);
                logger.info("  - Rs485_PollMs: 1000 (Pending)");
                logger.info("  - UWB_AlarmMs: 5000 (Pending)");
                logger.info("  - VoiceAlarmMs: 3000 (Pending)");
                logger.info("  - UWB_IgnoreCm: 50 (Pending)");
                logger.info("  - UWB_AlarmCm: 200 (Pending)");

                // 模拟发送参数同步指令到设备
                sendParamSyncCommand(deviceId);

                logger.info("=== 设备上线参数同步测试完成 ===");
            }

        } catch (Exception e) {
            logger.error("设备上线参数同步测试异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 发送参数同步指令到设备
     * V2.0.1: 下行Topic格式: WgtRfid/server/${deviceId}
     */
    private void sendParamSyncCommand(String deviceId) {
        try {
            if (mqttClient == null || !mqttClient.isConnected()) {
                logger.warn("MQTT客户端未连接，无法发送参数同步指令");
                return;
            }

            // 构建参数同步指令
            JSONObject paramSyncJson = new JSONObject();
            paramSyncJson.put("messageType", "param_write");
            paramSyncJson.put("seqNum", System.currentTimeMillis());

            // 参数列表
            JSONObject params = new JSONObject();
            params.put("Rs485_PollMs", 1000);
            params.put("UWB_AlarmMs", 5000);
            params.put("VoiceAlarmMs", 3000);
            params.put("UWB_IgnoreCm", 50);
            params.put("UWB_AlarmCm", 200);
            paramSyncJson.put("params", params);

            String payload = paramSyncJson.toJSONString();
            String downlinkTopic = TOPIC_SERVER_DOWNLINK_PREFIX + deviceId;

            MqttMessage message = new MqttMessage(payload.getBytes());
            message.setQos(QOS);

            mqttClient.publish(downlinkTopic, message);
            logger.info("参数同步指令已发送 - DeviceID: {}, Topic: {}, Payload: {}",
                    deviceId, downlinkTopic, payload);

        } catch (Exception e) {
            logger.error("发送参数同步指令异常: {}", e.getMessage(), e);
        }
    }
}
