package com.evobms.project.bms.service;

import com.alibaba.fastjson2.JSON;
import com.evobms.common.utils.DateUtils;
import com.evobms.project.battery.domain.ExtremeValues;
import com.evobms.project.battery.domain.SubsystemTemperature;
import com.evobms.project.battery.domain.SubsystemVoltage;
import com.evobms.project.battery.service.IExtremeValuesService;
import com.evobms.project.battery.service.ISubsystemTemperatureService;
import com.evobms.project.battery.service.ISubsystemVoltageService;
import com.evobms.project.bms.domain.*;
import com.evobms.project.bms.mapper.BmsVoltageChannelDataMapper;
import com.evobms.project.summary.domain.ChargeDischargeSummary;
import com.evobms.project.summary.service.IChargeDischargeSummaryService;
import com.evobms.project.system.domain.BmsDevices;
import com.evobms.project.system.mapper.BmsDevicesMapper;
import com.evobms.project.system.service.IBmsDevicesService;
import com.evobms.project.vehicledata.domain.VehicleData;
import com.evobms.project.vehicledata.domain.VehicleLocation;
import com.evobms.project.vehicledata.service.IVehicleDataService;
import com.evobms.project.vehicledata.service.IVehicleLocationService;
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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;
import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.*;
import java.util.stream.Collectors;

import static com.evobms.project.bms.controller.GBT32960FullDecoder.parseGBT32960Data;

/**
 * MQTT服务类
 * 只有在mqtt.enabled=true时才会加载此服务
 *
 * @author evobms
 */
@Service
@ConditionalOnProperty(name = "mqtt.enabled", havingValue = "true")
public class MqttService {
    private static final Logger log = LoggerFactory.getLogger(MqttService.class);
    @Autowired
    private MessageChannel mqttOutboundChannel;
    @Autowired
    private IBmsDevicesService bmsDevicesService;
    @Autowired
    private IVehicleDataService vehicleDataService;
    @Autowired
    private IVehicleLocationService vehicleLocationService;
    @Autowired
    private IExtremeValuesService extremeValuesService;
    @Autowired
    private ISubsystemVoltageService subsystemVoltageService;
    @Autowired
    private ISubsystemTemperatureService subsystemTemperatureService;
    @Autowired
    private IChargeDischargeSummaryService chargeDischargeSummaryService;
    @Autowired
    private IBmsChargeDetailService bmsChargeDetailService;
    @Autowired
    private IBmsRuntimeDataService bmsRuntimeDataService;
    @Autowired
    private IBmsSopDataService bmsSopDataService;
    @Autowired
    private IBmsSystemStatusService bmsSystemStatusService;
    @Autowired
    private IBmsChargeTemperatureService bmsChargeTemperatureService;
    @Autowired
    private BmsVoltageChannelDataMapper bmsVoltageChannelDataMapper;
    @Autowired
    private IBmsVoltageChannelDataService bmsVoltageChannelDataService;

    @Autowired
    private BmsDevicesMapper bmsDevicesMapper;

    @Value("${mqtt.publishTopic}")
    private String publishTopic;

    @Value("${mqtt.defaultQos}")
    private int defaultQos;

    @Value("${mqtt.dataHeaderLength:12}")
    private int dataHeaderLength;

    private static String toHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString().trim();
    }

    private static byte[] parseHex(String hex) {
        String cleaned = hex.replaceAll("[^0-9A-Fa-f]", "");
        if ((cleaned.length() % 2) != 0) {
            throw new IllegalArgumentException("HEX长度不是偶数");
        }
        int len = cleaned.length() / 2;
        byte[] out = new byte[len];
        for (int i = 0; i < len; i++) {
            int hi = Character.digit(cleaned.charAt(2 * i), 16);
            int lo = Character.digit(cleaned.charAt(2 * i + 1), 16);
            out[i] = (byte) ((hi << 4) | lo);
        }
        return out;
    }

    private static byte computeBcc(byte[] buf, int startInclusive, int endExclusive) {
        byte b = 0;
        for (int i = startInclusive; i < endExclusive; i++) {
            b ^= buf[i];
        }
        return b;
    }

    private static byte[] deriveKeyFromSn(String sn) {
        byte[] key = new byte[16];
        byte[] snBytes = sn == null ? new byte[0] : sn.getBytes(StandardCharsets.UTF_8);
        int copy = Math.min(snBytes.length, 16);
        System.arraycopy(snBytes, 0, key, 0, copy);
        return key;
    }

    private static byte[] aesEcbPkcs5Decrypt(byte[] ciphertext, byte[] key) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec spec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, spec);
        return cipher.doFinal(ciphertext);
    }

    private static byte[] aesEcbPkcs5Encrypt(byte[] plaintext, byte[] key) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec spec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, spec);
        return cipher.doFinal(plaintext);
    }

    /**
     * 发送MQTT消息
     *
     * @param topic   主题
     * @param payload 消息内容
     */
    public void sendMessage(String topic, String payload) {
        log.info("发送MQTT消息 -> 主题: {}, QOS: {}, 载荷: {}", topic, defaultQos, payload);
        mqttOutboundChannel.send(MessageBuilder.withPayload(payload).setHeader("mqtt_topic", topic).setHeader("mqtt_qos", defaultQos).build());
    }

    /**
     * 发送MQTT字节消息
     *
     * @param topic   主题
     * @param payload 原始字节
     */
    public void sendMessageBytes(String topic, byte[] payload) {
        log.info("发送MQTT字节消息 -> 主题: {}, QOS: {}, 长度: {}, HEX: {}", topic, defaultQos, payload.length, toHex(payload));
        mqttOutboundChannel.send(MessageBuilder.withPayload(payload).setHeader("mqtt_topic", topic).setHeader("mqtt_qos", defaultQos).build());
    }

    /**
     * 发送设备控制命令
     *
     * @param deviceCode 设备编号
     * @param command    控制命令
     */
    public void sendDeviceCommand(String deviceCode, String command) {
        Map<String, Object> commandData = new HashMap<>();
        commandData.put("deviceCode", deviceCode);
        commandData.put("command", command);
        commandData.put("timestamp", new Date());

        String topic = "evobms/" + deviceCode + "/command";
        String payload = JSON.toJSONString(commandData);

        sendMessage(topic, payload);
    }

    /**
     * 处理接收到的设备数据
     *
     * @param topic   主题
     * @param message 消息内容
     */
    public void handleDeviceData(String topic, byte[] message) {
        try {
            // 从主题提取设备唯一编号（紧跟在"bbox"后面的段）
            String[] topicParts = topic.split("/");
            String deviceCode = null;
            for (int i = 0; i < topicParts.length - 1; i++) {
                if ("bbox".equalsIgnoreCase(topicParts[i])) {
                    deviceCode = topicParts[i + 1];
                    break;
                }
            }
            if (deviceCode == null) {
                // 兜底：考虑有无前导斜杠
                deviceCode = topicParts[topic.startsWith("/") ? 2 : 1];
            }

            log.info("处理设备数据 -> 设备: {}, 主题: {}, 长度: {}", deviceCode, topic, message == null ? 0 : message.length);

            // 根据设备唯一编号查询系统表的SN码；查询不到则回退使用deviceCode
            String deviceSn = lookupDeviceSnByCode(deviceCode);
            if (deviceSn == null || deviceSn.isEmpty()) {
                deviceSn = deviceCode;
            }

            // 直接解析GB/T 32960二进制帧
            String data = parseGBT32960Data(message, deviceSn);
            // 逐字段解析返回的data字符串
            parseDataFields(data, deviceSn);
        } catch (Exception e) {
            log.error("处理设备数据时发生错误: {}", e.getMessage(), e);
        }
    }

    /**
     * 逐字段解析数据字符串 - 直接解析十六进制数据
     *
     * @param data     十六进制数据字符串
     * @param deviceSn 设备SN码
     */
    private void parseDataFields(String data, String deviceSn) {
        if (data == null || data.isEmpty()) {
            log.warn("设备 {}: 无有效数据可解析", deviceSn);
            return;
        }
        try {
            log.info("设备 {} 原始数据: {}", deviceSn, data);

            // 清理数据，移除非十六进制字符
            String cleanData = data.replaceAll("[^0-9A-Fa-f]", "");

            if (cleanData.length() < 4) {
                log.warn("设备 {}: 数据长度不足", deviceSn);
                return;
            }

            // 将十六进制字符串转换为字节数组
            byte[] message = hexStringToByteArray(cleanData);
            if (message.length >= 3 && (message[0] & 0xFF) == 0xAA && (message[1] & 0xFF) == 0x55 && (message[2] & 0xFF) == 0xA5) {
                log.info("设备 {} 调试无效帧(AA 55 A5)，跳过", deviceSn);
                return;
            }

            // 按照协议索引逐段解析
            parseByProtocolIndex(message, deviceSn);

        } catch (Exception e) {
            log.error("设备 {} 解析数据字段时发生错误: {}", deviceSn, e.getMessage(), e);
        }
    }

    /**
     * 按照协议定义的索引位置解析各个数据段
     */
    private void parseByProtocolIndex(byte[] message, String deviceSn) {
        try {
            // 1.时间戳- 索引24-29 (6字节)
            Date frameTime = parseTimeAtIndex(message, 0, deviceSn);
            if (frameTime == null) {
                frameTime = new Date();
            }

            // 2. 整车数据 - 绝对索引30-49(20字节) | 相对偏移: 6-25
            parseVehicleDataAtIndex(message, 6, deviceSn, frameTime);

            // 3. 位置信息 - 绝对索引51-60(10字节) | 相对偏移: 27-36
            parseLocationDataAtIndex(message, 27, deviceSn, frameTime);

            // 4. 极值数据 - 绝对索引61-75(15字节) | 相对偏移: 37-51
            parseExtremeDataAtIndex(message, 37, deviceSn, frameTime);

            // 5. 单体电压数据 - 绝对索引76-447(372字节) | 相对偏移: 52-423
            parseCellVoltageAtIndex(message, 52, deviceSn, frameTime);

            // 6. 单体温度数据 - 绝对索引448-542(95字节) | 相对偏移: 424-518
            parseCellTemperatureAtIndex(message, 424, deviceSn, frameTime);

            // 7. 累计充放电量 - 绝对索引543-553(11字节) | 相对偏移: 519-529
            parseChargeDischargeAtIndex(message, 519, deviceSn, frameTime);

            parseExtendedDataAtIndex(message, 506, deviceSn, frameTime);

            log.info("设备 {} 所有数据段解析完成", deviceSn);

        } catch (Exception e) {
            log.error("设备 {} 按索引解析时发生错误: {}", deviceSn, e.getMessage(), e);
        }
    }

    /**
     * 解析时间信息 - 绝对索引24-29(6字节) | 相对偏移: 0-5
     * 格式: 年(偏移2000) + 月 + 日 + 时 + 分 + 秒
     */
    private Date parseTimeAtIndex(byte[] message, int startIndex, String deviceSn) {
        try {
            if (message.length < startIndex + 6) {
                log.warn("设备 {}: 时间数据索引越界", deviceSn);
                return null;
            }

            int year = (message[startIndex] & 0xFF) + 2000;     // 索引24: 年
            int month = message[startIndex + 1] & 0xFF;         // 索引25: 月
            int day = message[startIndex + 2] & 0xFF;           // 索引26: 日
            int hour = message[startIndex + 3] & 0xFF;          // 索引27: 时
            int minute = message[startIndex + 4] & 0xFF;        // 索引28: 分
            int second = message[startIndex + 5] & 0xFF;        // 索引29: 秒

            if (isValidTime(year, month, day, hour, minute, second)) {
                String time = String.format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
                log.info("设备 {} - 时间: {}", deviceSn, time);
                saveTimeData(deviceSn, time);
                Calendar cal = Calendar.getInstance(TimeZone.getDefault());
                cal.set(year, month - 1, day, hour, minute, second);
                cal.set(Calendar.MILLISECOND, 0);
                return cal.getTime();
            } else {
                log.info("设备 {} - 时间: 无效数据({}-{}-{} {}:{}:{})", deviceSn, year, month, day, hour, minute, second);
                return null;
            }

        } catch (Exception e) {
            log.error("设备 {} 解析时间数据时发生错误: {}", deviceSn, e.getMessage());
            return null;
        }
    }

    /**
     * 解析整车数据 - 绝对索引30-49(20字节) | 相对偏移: 6-25
     */
    private void parseVehicleDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
        try {
            if (message.length < startIndex + 20) {
                log.warn("设备 {}: 整车数据索引越界", deviceSn);
                return;
            }

            // 索引30: 数据标识 (应该是0x01)
            byte dataFlag = message[startIndex];
            if (dataFlag != 0x01) {
                log.warn("设备 {}: 整车数据标识错误: 0x{}", deviceSn, String.format("%02X", dataFlag));
                return;
            }

            log.info("设备 {} - 发现整车数据", deviceSn);

            // 索引32: 充电状态
            byte chargeStatus = message[startIndex + 2];
            log.info("设备 {} - 充电状态: 0x{} ({})", deviceSn, String.format("%02X", chargeStatus), getChargeStatusDescription(chargeStatus));

            // 索引40-41: 总电压 (0.1V)
            int totalVoltage = ((message[startIndex + 10] & 0xFF) << 8) | (message[startIndex + 11] & 0xFF);
            double voltageValue = totalVoltage * 0.1;
            log.info("设备 {} - 总电压: {} V", deviceSn, voltageValue);

            // 索引42-43: 总电流 (0.1A, 偏移10000)
            int totalCurrent = ((message[startIndex + 12] & 0xFF) << 8) | (message[startIndex + 13] & 0xFF);
            double currentValue = (totalCurrent - 10000) * 0.1;
            log.info("设备 {} - 总电流: {} A", deviceSn, currentValue);

            // 索引44: SOC (%)
            int soc = message[startIndex + 14] & 0xFF;
            log.info("设备 {} - SOC: {} %", deviceSn, soc);

            // 索引47-48: 正极绝缘电阻 (Ω)
            int insulationResistance = ((message[startIndex + 17] & 0xFF) << 8) | (message[startIndex + 18] & 0xFF);
            log.info("设备 {} - 正极绝缘电阻: {} Ω", deviceSn, insulationResistance);

            // 保存整车数据
            saveVehicleData(deviceSn, voltageValue, currentValue, soc, chargeStatus, insulationResistance, frameTime);

        } catch (Exception e) {
            log.error("设备 {} 解析整车数据时发生错误: {}", deviceSn, e.getMessage());
        }
    }


    /**
     * 解析位置信息 - 绝对索引51-60(10字节) | 相对偏移: 27-36
     */
    private void parseLocationDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
        try {
            if (message.length < startIndex + 10) {
                log.warn("设备 {}: 位置数据索引越界", deviceSn);
                return;
            }

            // 索引51: 数据标识 (应该是0x05)
            byte dataFlag = message[startIndex];
            if (dataFlag != 0x05) {
                log.warn("设备 {}: 位置数据标识错误: 0x{}", deviceSn, String.format("%02X", dataFlag));
                return;
            }

            log.info("设备 {} - 发现位置信息", deviceSn);

            // 索引52: 位置状态
            byte locationStatus = message[startIndex + 1];
            // 转成十六进制字符串，例如 "00", "01"
            String locationStatusHex = String.format("%02X", locationStatus);
            // 索引53-56: 经度 (0.000001°)
            long longitude = ((message[startIndex + 2] & 0xFFL) << 24) | ((message[startIndex + 3] & 0xFFL) << 16) | ((message[startIndex + 4] & 0xFFL) << 8) | (message[startIndex + 5] & 0xFFL);

            // 索引57-60: 纬度 (0.000001°)
            long latitude = ((message[startIndex + 6] & 0xFFL) << 24) | ((message[startIndex + 7] & 0xFFL) << 16) | ((message[startIndex + 8] & 0xFFL) << 8) | (message[startIndex + 9] & 0xFFL);

            if (longitude != 0 || latitude != 0) {
                double lon = longitude / 1000000.0;
                double lat = latitude / 1000000.0;

                log.info("设备 {} - 位置: 经度={}°, 纬度={}° (状态:0x{})", deviceSn, lon, lat, locationStatusHex);
                processLocationData(deviceSn, lon, lat, locationStatusHex, frameTime);
            } else {
                log.info("设备 {} - 位置: 无效数据", deviceSn);
            }

        } catch (Exception e) {
            log.error("设备 {} 解析位置数据时发生错误: {}", deviceSn, e.getMessage());
        }
    }

    /**
     * 解析极值数据 - 绝对索引61-75(15字节) | 相对偏移: 37-51
     */
    private void parseExtremeDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
        try {
            if (message.length < startIndex + 14) {
                log.warn("设备 {}: 极值数据索引越界", deviceSn);
                return;
            }

            // 索引61: 数据标识 (应该是0x06)
            byte dataFlag = message[startIndex];
            if (dataFlag != 0x06) {
                log.warn("设备 {}: 极值数据标识错误: 0x{}", deviceSn, String.format("%02X", dataFlag));
                return;
            }

            log.info("设备 {} - 发现极值数据", deviceSn);

            // 索引62: 最高电压子系统号
            byte maxVoltageSystem = message[startIndex + 1];
            // 索引63: 最高电压探针号
            byte maxVoltageProbe = message[startIndex + 2];
            // 索引64-65: 最高单体电压 (mV)
            double maxVoltage = ((message[startIndex + 3] & 0xFF) << 8) | (message[startIndex + 4] & 0xFF);
            double maxVoltageValue = maxVoltage * 0.001; // 转换为V
            log.info("设备 {} - 最高电压: 子系统{}-探针{}, {}V", deviceSn, maxVoltageSystem, maxVoltageProbe, maxVoltageValue);

            // 索引66: 最低电压子系统号
            byte minVoltageSystem = message[startIndex + 5];
            // 索引67: 最低电压探针号
            byte minVoltageProbe = message[startIndex + 6];
            // 索引68-69: 最低单体电压 (mV)
            double minVoltage = ((message[startIndex + 7] & 0xFF) << 8) | (message[startIndex + 8] & 0xFF);
            double minVoltageValue = minVoltage * 0.001; // 转换为V
            log.info("设备 {} - 最低电压: 子系统{}-探针{}, {}V", deviceSn, minVoltageSystem, minVoltageProbe, minVoltageValue);
            // 索引70: 最高温度子系统号
            byte maxTempSystem = message[startIndex + 9];
            // 索引71: 最高温度探针号
            byte maxTempProbe = message[startIndex + 10];
            // 索引72: 最高单体温度 (偏移40°C)
            int maxTemperature = message[startIndex + 11] & 0xFF;
            int maxTempValue = maxTemperature - 40;
            log.info("设备 {} - 最高温度: 子系统{}-探针{}, {}°C", deviceSn, maxTempSystem, maxTempProbe, maxTempValue);
            // 索引73: 最低温度子系统号
            byte minTempSystem = message[startIndex + 12];
            // 索引74: 最低温度探针号
            byte minTempProbe = message[startIndex + 13];
            // 索引75: 最低单体温度 (偏移40°C)
            int minTemperature = message[startIndex + 14] & 0xFF;
            int minTempValue = minTemperature - 40;
            log.info("设备 {} - 最低温度: 子系统{}-探针{}, {}°C", deviceSn, minTempSystem, minTempProbe, minTempValue);
            // 保存极值数据
            saveExtremeData(deviceSn, (maxVoltageSystem & 0xFF), (maxVoltageProbe & 0xFF), maxVoltageValue, (minVoltageSystem & 0xFF), (minVoltageProbe & 0xFF), minVoltageValue, (maxTempSystem & 0xFF), (maxTempProbe & 0xFF), maxTempValue, (minTempSystem & 0xFF), (minTempProbe & 0xFF), minTempValue, frameTime);

        } catch (Exception e) {
            log.error("设备 {} 解析极值数据时发生错误: {}", deviceSn, e.getMessage());
        }
    }


    /**
     * 解析单体电压数据 - 绝对索引76-447(372字节) | 相对偏移: 52-423
     */
    private void parseCellVoltageAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
        try {
            if (message.length < startIndex + 372) {
                log.warn("设备 {}: 单体电压数据索引越界", deviceSn);
                return;
            }

            // 索引76: 数据标识 (应该是0x08)
            byte dataFlag = message[startIndex];
            if (dataFlag != 0x08) {
                log.warn("设备 {}: 单体电压数据标识错误: 0x{}", deviceSn, String.format("%02X", dataFlag));
                return;
            }

            log.info("设备 {} - 发现单体电压数据", deviceSn);

            // 索引77: 可充电储能子系统个数
            byte subsystemCount = message[startIndex + 1];
            // 索引78: 可充电储能子系统号
            byte subsystemNum = message[startIndex + 2];

            // 索引79-80: 可充电储能装置总压 (0.1V)
            int storageVoltage = ((message[startIndex + 3] & 0xFF) << 8) | (message[startIndex + 4] & 0xFF);
            double storageVoltageValue = storageVoltage * 0.1;

            // 索引81-82: 可充电储能装置总流 (0.1A, 偏移10000)
            int storageCurrent = ((message[startIndex + 5] & 0xFF) << 8) | (message[startIndex + 6] & 0xFF);
            double storageCurrentValue = (storageCurrent - 10000) * 0.1;

            log.info("设备 {} - 储能装置: 子系统{}/{}, 电压{}V, 电流{}A", deviceSn, subsystemNum, subsystemCount, storageVoltageValue, storageCurrentValue);

            // 索引83-84: 单体电压总数
            int totalCellCount = ((message[startIndex + 7] & 0xFF) << 8) | (message[startIndex + 8] & 0xFF);
            // 索引85-86: 本帧起始电芯序号
            int startCellIndex = ((message[startIndex + 9] & 0xFF) << 8) | (message[startIndex + 10] & 0xFF);
            // 索引87: 本帧电芯总数
            int frameCellCount = message[startIndex + 11] & 0xFF;

            log.info("设备 {} - 电芯信息: 总数{}个, 本帧{}-{}", deviceSn, totalCellCount, startCellIndex, startCellIndex + frameCellCount - 1);

            // 索引88开始: 单体电压数据 (每个电芯2字节)
            int voltageDataStart = startIndex + 12;
            boolean hasValidVoltage = checkCellVoltagesValid(message, voltageDataStart, frameCellCount);

            if (hasValidVoltage) {
                log.info("设备 {} - 发现有效单体电压数据", deviceSn);
                List<Double> voltages = new ArrayList<>();
                for (int i = 0; i < frameCellCount; i++) {
                    int v = ((message[voltageDataStart + i * 2] & 0xFF) << 8) | (message[voltageDataStart + i * 2 + 1] & 0xFF);
                    double vv = v * 0.001;
                    voltages.add(vv);
                }
                SubsystemVoltage sv = new SubsystemVoltage();
                sv.setDeviceId(deviceSn);
                sv.setTimestamp(frameTime);
                sv.setSubsystemCount((int) subsystemCount);
                sv.setSubsystemNo((int) subsystemNum);
                sv.setSubsystemVoltage(BigDecimal.valueOf(storageVoltageValue));
                sv.setSubsystemCurrent(BigDecimal.valueOf(storageCurrentValue));
                sv.setTotalBatteryCount(totalCellCount);
                sv.setFrameStartBatteryNo(startCellIndex);
                sv.setFrameBatteryCount(frameCellCount);
                sv.setCreateTime(new Date());
                sv.setCreateBy(deviceSn);
                String voltagesStr = voltages.stream().map(Object::toString).collect(java.util.stream.Collectors.joining(","));
                sv.setBatteryVoltages(JSON.toJSONString(voltagesStr));
                subsystemVoltageService.insertSubsystemVoltage(sv);
                parseCellVoltagesDetail(message, voltageDataStart, deviceSn, startCellIndex, frameCellCount);
            } else {
                log.info("设备 {} - 单体电压数据: 全部为0V", deviceSn);
            }

        } catch (Exception e) {
            log.error("设备 {} 解析单体电压数据时发生错误: {}", deviceSn, e.getMessage());
        }
    }


    /**
     * 解析单体温度数据 - 绝对索引448-542(95字节) | 相对偏移: 424-518
     */
    private void parseCellTemperatureAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
        try {
            if (message.length < startIndex + 89) {
                log.warn("设备 {}: 单体温度数据索引越界", deviceSn);
                return;
            }

            // 索引448: 数据标识 (应该是0x09)
            byte dataFlag = message[startIndex];
            if (dataFlag != 0x09) {
                log.warn("设备 {}: 单体温度数据标识错误: 0x{}", deviceSn, String.format("%02X", dataFlag));
                return;
            }

            log.info("设备 {} - 发现单体温度数据", deviceSn);

            // 索引449: 可充电储能子系统个数
            byte subsystemCount = message[startIndex + 1];
            // 索引450: 可充电储能子系统号
            byte subsystemNum = message[startIndex + 2];

            // 索引451-452: 单体温度总数
            int totalTempCount = ((message[startIndex + 3] & 0xFF) << 8) | (message[startIndex + 4] & 0xFF);

            log.info("设备 {} - 温度探头: 子系统{}/{}, 总数{}个", deviceSn, subsystemNum, subsystemCount, totalTempCount);

            // 索引453开始: 单体温度数据 (每个探头1字节)
            int tempDataStart = startIndex + 5;
            boolean hasValidTemperature = checkCellTemperaturesValid(message, tempDataStart, totalTempCount);

            if (hasValidTemperature) {
                log.info("设备 {} - 发现有效单体温度数据", deviceSn);
                List<Integer> temperatures = new ArrayList<>();
                for (int i = 0; i < totalTempCount; i++) {
                    int t = message[tempDataStart + i] & 0xFF;
                    int tv = t - 40;
                    temperatures.add(tv);
                }
                SubsystemTemperature st = new SubsystemTemperature();
                st.setDeviceId(deviceSn);
                st.setTimestamp(frameTime);
                st.setSubsystemCount((int) subsystemCount);
                st.setSubsystemNo((int) subsystemNum);
                st.setTempProbeCount(totalTempCount);
                st.setCreateTime(new Date());
                st.setCreateBy(deviceSn);
                String tempsStr = temperatures.stream().map(Object::toString).collect(Collectors.joining(","));
                st.setTemperatureValues(JSON.toJSONString(tempsStr));
                subsystemTemperatureService.insertSubsystemTemperature(st);
                parseCellTemperaturesDetail(message, tempDataStart, deviceSn, totalTempCount);
            } else {
                log.info("设备 {} - 单体温度数据: 全部为无效值", deviceSn);
            }

        } catch (Exception e) {
            log.error("设备 {} 解析单体温度数据时发生错误: {}", deviceSn, e.getMessage());
        }
    }

    /**
     * 解析累计充放电量 - 绝对索引543-553(11字节) | 相对偏移: 519-529
     */
    private void parseChargeDischargeAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
        try {
            if (message.length < startIndex + 11) {
                log.warn("设备 {}: 充放电数据索引越界", deviceSn);
                return;
            }
            // 索引543: 数据标识 (应该是0x80)
            byte dataFlag = message[startIndex];
            if (dataFlag != (byte) 0x80) {
                log.warn("设备 {}: 充放电数据标识错误: 0x{}", deviceSn, String.format("%02X", dataFlag));
                return;
            }

            log.info("设备 {} - 发现累计充放电数据", deviceSn);

            // 跳过索引544-545的保留字节
            // 索引546-549: 累计放电电量 (0.1kWh)
            long dischargeEnergy = ((message[startIndex + 3] & 0xFFL) << 24) | ((message[startIndex + 4] & 0xFFL) << 16) | ((message[startIndex + 5] & 0xFFL) << 8) | (message[startIndex + 6] & 0xFFL);

            // 索引550-553: 累计充电电量 (0.1kWh)
            long chargeEnergy = ((message[startIndex + 7] & 0xFFL) << 24) | ((message[startIndex + 8] & 0xFFL) << 16) | ((message[startIndex + 9] & 0xFFL) << 8) | (message[startIndex + 10] & 0xFFL);

            double dischargeKwh = dischargeEnergy * 0.1;
            double chargeKwh = chargeEnergy * 0.1;

            log.info("设备 {} - 累计充放电量: 放电{}kWh, 充电{}kWh", deviceSn, dischargeKwh, chargeKwh);

            saveChargeDischargeSummary(deviceSn, dischargeKwh, chargeKwh, frameTime);

        } catch (Exception e) {
            log.error("设备 {} 解析充放电数据时发生错误: {}", deviceSn, e.getMessage());
        }
    }


    /**
     * 解析详细的单体温度数据
     */
    private void parseCellTemperaturesDetail(byte[] message, int startIndex, String deviceSn, int tempCount) {
        List<Integer> temperatures = new ArrayList<>();

        for (int i = 0; i < tempCount; i++) {
            int temperature = message[startIndex + i] & 0xFF;
            int tempValue = temperature - 40; // 温度偏移量
            temperatures.add(tempValue);

            // 记录前几个温度用于调试
            if (i < 5) {
                log.debug("设备 {} - 温度探头{}: {}°C", deviceSn, i + 1, tempValue);
            }
        }

        // 计算统计信息
        int minTemp = temperatures.stream().mapToInt(v -> v).min().orElse(0);
        int maxTemp = temperatures.stream().mapToInt(v -> v).max().orElse(0);
        double avgTemp = temperatures.stream().mapToInt(v -> v).average().orElse(0);

        log.info("设备 {} - 温度统计: 最小值{}°C, 最大值{}°C, 平均值{}°C", deviceSn, minTemp, maxTemp, avgTemp);
    }


    /**
     * 检查单体温度数据有效性
     */
    private boolean checkCellTemperaturesValid(byte[] message, int startIndex, int tempCount) {
        for (int i = 0; i < tempCount; i++) {
            int temperature = message[startIndex + i] & 0xFF;
            if (temperature != 0 && temperature != 0xFF) {
                return true;
            }
        }
        return false;
    }

    /**
     * 解析详细的单体电压数据
     */
    private void parseCellVoltagesDetail(byte[] message, int startIndex, String deviceSn, int startCellIndex, int cellCount) {
        List<Double> voltages = new ArrayList<>();

        for (int i = 0; i < cellCount; i++) {
            int voltage = ((message[startIndex + i * 2] & 0xFF) << 8) | (message[startIndex + i * 2 + 1] & 0xFF);
            double voltageValue = voltage * 0.001; // mV转V
            voltages.add(voltageValue);

            // 记录前几个电芯电压用于调试
            if (i < 5) {
                log.debug("设备 {} - 电芯{}电压: {}V", deviceSn, startCellIndex + i, voltageValue);
            }
        }

        // 计算统计信息
        double minVoltage = voltages.stream().mapToDouble(v -> v).min().orElse(0);
        double maxVoltage = voltages.stream().mapToDouble(v -> v).max().orElse(0);
        double avgVoltage = voltages.stream().mapToDouble(v -> v).average().orElse(0);

        log.info("设备 {} - 电压统计: 最小值{}V, 最大值{}V, 平均值{}V", deviceSn, minVoltage, maxVoltage, avgVoltage);
    }

    /**
     * 检查单体电压数据有效性
     */
    private boolean checkCellVoltagesValid(byte[] message, int startIndex, int cellCount) {
        for (int i = 0; i < cellCount * 2; i += 2) {
            int voltage = ((message[startIndex + i] & 0xFF) << 8) | (message[startIndex + i + 1] & 0xFF);
            if (voltage > 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 充电状态描述
     */
    private int getChargeStatusDescription(byte status) {
        /** 充电状态 (1:停车充电 2:行驶充电 3:未充电 4:充电完成 254:异常 255:无效) */
        switch (status & 0xFF) {
            case 0x01:
                return 1;
            case 0x02:
                return 2;
            case 0x03:
                return 3;
            case 0x04:
                return 4;
            case 0xFE:
                return 254;
            case 0xFF:
                return 255;

        }
        return 0;
    }

    /**
     * 检查时间有效性
     */
    private boolean isValidTime(int year, int month, int day, int hour, int minute, int second) {
        return year >= 2000 && year <= 2100 && month >= 1 && month <= 12 && day >= 1 && day <= 31 && hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59;
    }

    /**
     * 十六进制字符串转字节数组
     */
    private byte[] hexStringToByteArray(String hex) {
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }


    /**
     * 保存单体电压数据
     */
    private void saveCellVoltageData(String deviceSn, byte subsystemNum, int startIndex, int count, List<Double> voltages, double min, double max, double avg) {
        // TODO: 实现单体电压数据保存逻辑
        log.debug("保存设备 {} 子系统 {} 电压数据: 起始{}, 数量{}, 范围{}-{}V", deviceSn, subsystemNum, startIndex, count, min, max);
    }

    /**
     * 保存单体温度数据
     */
    private void saveCellTemperatureData(String deviceSn, byte subsystemNum, int count, List<Integer> temperatures, int min, int max, double avg) {
        // TODO: 实现单体温度数据保存逻辑
        log.debug("保存设备 {} 子系统 {} 温度数据: 数量{}, 范围{}-{}°C", deviceSn, subsystemNum, count, min, max);
    }

    /**
     * 保存时间数据
     */
    private void saveTimeData(String deviceSn, String time) {
        try {
            Date ts = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, time);
            if (ts == null) {
                log.warn("设备 {} 时间解析失败: {}", deviceSn, time);
                return;
            }
            BmsDevices existing = bmsDevicesService.selectBmsDevicesBySn(deviceSn);
            if (existing != null) {
                existing.setLastOnline(ts);
                existing.setStatus("online");
                existing.setUpdateTime(new Date());
                bmsDevicesMapper.updateBmsDevices(existing);
            } else {
                BmsDevices dev = new BmsDevices();
                dev.setDeviceSn(deviceSn);
                dev.setStatus("online");
                dev.setLastOnline(ts);
                dev.setCreateTime(new Date());
                bmsDevicesMapper.insertBmsDevices(dev);
            }
            log.debug("保存设备 {} 时间数据: {}", deviceSn, time);
        } catch (Exception e) {
            log.error("保存设备 {} 时间数据失败: {}", deviceSn, e.getMessage(), e);
        }
    }

    /**
     * 保存整车数据
     */
    private void saveVehicleData(String deviceSn, double voltage, double current, int soc, byte chargeStatus, int insulationResistance, Date frameTime) {
        // 保存整车数据到数据库
        VehicleData ve = new VehicleData();
        ve.setDeviceId(deviceSn);
        ve.setTimestamp(frameTime);
        ve.setTotalVoltage(BigDecimal.valueOf(voltage));
        ve.setTotalCurrent(BigDecimal.valueOf(current));
        ve.setSoc(soc);
        ve.setChargingStatus(getChargeStatusDescription(chargeStatus));
        ve.setInsulationResistance(insulationResistance);
        ve.setCreateTime(new Date());
        ve.setCreateBy(deviceSn);
        vehicleDataService.insertVehicleData(ve);
    }


    private void processLocationData(String deviceSn, double longitude, double latitude, String locationStatus, Date frameTime) {
        VehicleLocation ve = new VehicleLocation();
        ve.setDeviceId(deviceSn);
        ve.setTimestamp(frameTime);
        // 十六进制字符串（如 "00"）转成整数（如 0）
        int status = Integer.parseInt(locationStatus, 16);
        ve.setPositioningStatus(status);
        ve.setLongitude(BigDecimal.valueOf(longitude));
        ve.setLatitude(BigDecimal.valueOf(latitude));
        ve.setCreateTime(new Date());
        ve.setCreateBy(deviceSn);
        vehicleLocationService.insertVehicleLocation(ve);
    }

    private void saveExtremeData(String deviceSn, int maxVoltageSubsystemNo, int maxVoltageBatteryNo, double maxVoltageValue, int minVoltageSubsystemNo, int minVoltageBatteryNo, double minVoltageValue, int maxTempSubsystemNo, int maxTempProbeNo, int maxTempValue, int minTempSubsystemNo, int minTempProbeNo, int minTempValue, Date frameTime) {
        ExtremeValues ex = new ExtremeValues();
        ex.setDeviceId(deviceSn);
        ex.setTimestamp(frameTime);
        ex.setMaxVoltageSubsystemNo(maxVoltageSubsystemNo);
        ex.setMaxVoltageBatteryNo(maxVoltageBatteryNo);
        ex.setMaxVoltageValue(BigDecimal.valueOf(maxVoltageValue));
        ex.setMinVoltageSubsystemNo(minVoltageSubsystemNo);
        ex.setMinVoltageBatteryNo(minVoltageBatteryNo);
        ex.setMinVoltageValue(BigDecimal.valueOf(minVoltageValue));
        ex.setMaxTempSubsystemNo(maxTempSubsystemNo);
        ex.setMaxTempProbeNo(maxTempProbeNo);
        ex.setMaxTempValue(BigDecimal.valueOf(maxTempValue));
        ex.setMinTempSubsystemNo(minTempSubsystemNo);
        ex.setMinTempProbeNo(minTempProbeNo);
        ex.setMinTempValue(BigDecimal.valueOf(minTempValue));
        extremeValuesService.insertExtremeValues(ex);
    }

    private void saveChargeDischargeSummary(String deviceSn, double dischargeKwh, double chargeKwh, Date frameTime) {
        ChargeDischargeSummary s = new ChargeDischargeSummary();
        s.setDeviceId(deviceSn);
        s.setTimestamp(frameTime);
        s.setDischargeKwh(BigDecimal.valueOf(dischargeKwh));
        s.setChargeKwh(BigDecimal.valueOf(chargeKwh));
        s.setCreateTime(new Date());
        s.setCreateBy(deviceSn);
        chargeDischargeSummaryService.insertChargeDischargeSummary(s);
    }

    /**
     * 处理单体温度数据
     */
    private void processCellTemperatureData(String deviceSn, Map<String, String> fieldMap) {
        // TODO: 如果有详细的单体温度数据，在这里处理
    }

    /**
     * 保存充放电数据
     */
    private void saveChargeDischargeData(String deviceSn, String dischargeEnergy, String chargeEnergy, String time) {
        // TODO: 实现充放电数据保存逻辑
    }


    /**
     * 发送设备状态查询命令
     *
     * @param deviceCode 设备编号
     */
    public void queryDeviceStatus(String deviceCode) {
        sendDeviceCommand(deviceCode, "STATUS_QUERY");
    }

    /**
     * 扩展区块解析（BatteryData[530..716]）
     * 索引换算: 绝对索引abs → message索引 = startIndex + (abs - 530)
     * 单位与偏移:
     * - 电压/电流 ×0.1（除特殊 2.5V/5V 采样为 ×0.001）
     * - 温度值需减去 40（协议偏移）
     * - 车速 ×0.1 km/h
     * - 里程为 u32 原始值（单位由上位业务确定）
     */
    private void parseExtendedDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
        try {
            int need = (716 - 530 + 1);
            if (message.length < startIndex + need) {
                log.warn("设备 {}: 扩展数据索引越界", deviceSn);
                return;
            }
            // 系统计数/绝缘/车速/总压
            long resetCount = ((message[startIndex] & 0xFFL) << 24) | ((message[startIndex + 1] & 0xFFL) << 16) | ((message[startIndex + 2] & 0xFFL) << 8) | (message[startIndex + 3] & 0xFFL); // 复位次数(u32)
            int insulationVal = ((message[startIndex + 4] & 0xFF) << 8) | (message[startIndex + 5] & 0xFF); // 绝缘值(单位KΩ)
            int carSpdRaw = ((message[startIndex + 6] & 0xFF) << 8) | (message[startIndex + 7] & 0xFF); // 车速原始(×0.1km/h)
            double carSpd = carSpdRaw * 0.1;
            int gpvRaw = ((message[startIndex + 8] & 0xFF) << 8) | (message[startIndex + 9] & 0xFF); // GPV(×0.1V)
            double gpv = gpvRaw * 0.1;
            // RTP1..7(×0.1V)
            double rtp1 = (((message[startIndex + 10] & 0xFF) << 8) | (message[startIndex + 11] & 0xFF)) * 0.1;
            double rtp2 = (((message[startIndex + 12] & 0xFF) << 8) | (message[startIndex + 13] & 0xFF)) * 0.1;
            double rtp3 = (((message[startIndex + 14] & 0xFF) << 8) | (message[startIndex + 15] & 0xFF)) * 0.1;
            double rtp4 = (((message[startIndex + 16] & 0xFF) << 8) | (message[startIndex + 17] & 0xFF)) * 0.1;
            double rtp5 = (((message[startIndex + 18] & 0xFF) << 8) | (message[startIndex + 19] & 0xFF)) * 0.1;
            double rtp6 = (((message[startIndex + 20] & 0xFF) << 8) | (message[startIndex + 21] & 0xFF)) * 0.1;
            double rtp7 = (((message[startIndex + 22] & 0xFF) << 8) | (message[startIndex + 23] & 0xFF)) * 0.1;
            // RTN探针序号
            int rtn1 = message[startIndex + 24] & 0xFF; // RTN1
            int rtn2 = message[startIndex + 25] & 0xFF; // RTN2
            int rtn3 = message[startIndex + 26] & 0xFF; // RTN3
            int rtn4 = message[startIndex + 27] & 0xFF; // RTN4
            double realSocMax = (((message[startIndex + 28] & 0xFF) << 8) | (message[startIndex + 29] & 0xFF)) * 0.1; // RealSOC最大(×0.1%)
            double realSocMin = (((message[startIndex + 30] & 0xFF) << 8) | (message[startIndex + 31] & 0xFF)) * 0.1; // RealSOC最小(×0.1%)
            // 充电座温度(℃，需减40)
            int chgBs1Tmp = (message[startIndex + 32] & 0xFF) - 40;
            int chgBs2Tmp = (message[startIndex + 33] & 0xFF) - 40;
            int chgBs3Tmp = (message[startIndex + 34] & 0xFF) - 40;
            int chgBs4Tmp = (message[startIndex + 35] & 0xFF) - 40;
            int chgBs5Tmp = (message[startIndex + 36] & 0xFF) - 40;
            int chgBs6Tmp = (message[startIndex + 37] & 0xFF) - 40;
            int chgBs7Tmp = (message[startIndex + 38] & 0xFF) - 40;
            int chgBs8Tmp = (message[startIndex + 39] & 0xFF) - 40;
            // 慢充/快充电流电压(×0.1)
            double tChgCur = (((message[startIndex + 40] & 0xFF) << 8) | (message[startIndex + 41] & 0xFF)) * 0.1; // 慢充电流(A)
            double tChgVol = (((message[startIndex + 42] & 0xFF) << 8) | (message[startIndex + 43] & 0xFF)) * 0.1; // 慢充电压(V)
            double fChgCur = (((message[startIndex + 44] & 0xFF) << 8) | (message[startIndex + 45] & 0xFF)) * 0.1; // 快充电流(A)
            double fChgVol = (((message[startIndex + 46] & 0xFF) << 8) | (message[startIndex + 47] & 0xFF)) * 0.1; // 快充电压(V)
            // 放电/回馈SOP能力(A)
            long disSop10 = ((message[startIndex + 48] & 0xFF) << 8) | (message[startIndex + 49] & 0xFF);
            long disSop30 = ((message[startIndex + 50] & 0xFF) << 8) | (message[startIndex + 51] & 0xFF);
            long disSop60 = ((message[startIndex + 52] & 0xFF) << 8) | (message[startIndex + 53] & 0xFF);
            long disSopCont = ((message[startIndex + 54] & 0xFF) << 8) | (message[startIndex + 55] & 0xFF);
            long regSop10 = ((message[startIndex + 56] & 0xFF) << 8) | (message[startIndex + 57] & 0xFF);
            long regSop30 = ((message[startIndex + 58] & 0xFF) << 8) | (message[startIndex + 59] & 0xFF);
            long regSop60 = ((message[startIndex + 60] & 0xFF) << 8) | (message[startIndex + 61] & 0xFF);
            long regSopCont = ((message[startIndex + 62] & 0xFF) << 8) | (message[startIndex + 63] & 0xFF);
            long disSopTol = ((message[startIndex + 64] & 0xFF) << 8) | (message[startIndex + 65] & 0xFF);
            long regSopTol = ((message[startIndex + 66] & 0xFF) << 8) | (message[startIndex + 67] & 0xFF);
            // 版本与编码
            int hwVer = ((message[startIndex + 68] & 0xFF) << 8) | (message[startIndex + 69] & 0xFF); // 硬件版本
            int swVer = ((message[startIndex + 70] & 0xFF) << 8) | (message[startIndex + 71] & 0xFF); // 软件版本
            String bmsCode = readAsciiRange(message, 602, 28, startIndex); // BMS编码(28字节ASCII)
            String vin = readAsciiRange(message, 629, 21, startIndex); // VIN码(21字节ASCII)
            // 系统状态
            int sysVolRaw = ((message[startIndex + (649 - 530)] & 0xFF) << 8) | (message[startIndex + (650 - 530)] & 0xFF); // 系统电压(×0.1V)
            int sysCurRaw = ((message[startIndex + (651 - 530)] & 0xFF) << 8) | (message[startIndex + (652 - 530)] & 0xFF); // 系统电流(×0.1A)
            double sysVol = sysVolRaw * 0.1;
            double sysCur = sysCurRaw * 0.1;
            int cellCount = ((message[startIndex + (653 - 530)] & 0xFF) << 8) | (message[startIndex + (654 - 530)] & 0xFF);
            int tempSensorCount = ((message[startIndex + (655 - 530)] & 0xFF) << 8) | (message[startIndex + (656 - 530)] & 0xFF);
            int relayStatus = ((message[startIndex + (657 - 530)] & 0xFF) << 8) | (message[startIndex + (658 - 530)] & 0xFF);
            int onaaccStatus = ((message[startIndex + (659 - 530)] & 0xFF) << 8) | (message[startIndex + (660 - 530)] & 0xFF);
            int acStopCode = message[startIndex + (661 - 530)] & 0xFF;
            int dcStopCode = message[startIndex + (662 - 530)] & 0xFF;
            int cycleCount = ((message[startIndex + (663 - 530)] & 0xFF) << 8) | (message[startIndex + (664 - 530)] & 0xFF);
            long devId = ((message[startIndex + (665 - 530)] & 0xFFL) << 24) | ((message[startIndex + (666 - 530)] & 0xFFL) << 16) | ((message[startIndex + (667 - 530)] & 0xFFL) << 8) | (message[startIndex + (668 - 530)] & 0xFFL);
            String clientCode = readAsciiRange(message, 669, 28, startIndex); // 客户编码(28字节ASCII)
            double samp25v = (((message[startIndex + (696 - 530)] & 0xFF) << 8) | (message[startIndex + (697 - 530)] & 0xFF)) * 0.001; // 2.5V采样(×0.001V)
            double samp5v = (((message[startIndex + (698 - 530)] & 0xFF) << 8) | (message[startIndex + (699 - 530)] & 0xFF)) * 0.001; // 5V采样(×0.001V)
            long chargeSop = ((message[startIndex + (700 - 530)] & 0xFF) << 8) | (message[startIndex + (701 - 530)] & 0xFF); // 充电SOP(A)
            long acChargeSop = ((message[startIndex + (702 - 530)] & 0xFF) << 8) | (message[startIndex + (703 - 530)] & 0xFF); // 慢充SOP(A)
            // 运行阶段/充电阶段/时间与里程
            int runSts = message[startIndex + (704 - 530)] & 0xFF; // 行车阶段
            int runPwrSts = message[startIndex + (705 - 530)] & 0xFF; // 行车上电阶段
            int tChgCp = message[startIndex + (706 - 530)] & 0xFF; // 慢充CP值
            int tChgR = message[startIndex + (707 - 530)] & 0xFF; // 慢充枪阻值
            int tChgSts = message[startIndex + (708 - 530)] & 0xFF; // 慢充阶段
            int fChgSts2 = message[startIndex + (709 - 530)] & 0xFF; // 快充阶段
            int chgSts = message[startIndex + (710 - 530)] & 0xFF; // 充电阶段
            long chgTime = ((message[startIndex + (711 - 530)] & 0xFF) << 8) | (message[startIndex + (712 - 530)] & 0xFF); // 充电时长(min)
            long mileage = ((message[startIndex + (713 - 530)] & 0xFFL) << 24) | ((message[startIndex + (714 - 530)] & 0xFFL) << 16) | ((message[startIndex + (715 - 530)] & 0xFFL) << 8) | (message[startIndex + (716 - 530)] & 0xFFL); // 里程(u32)
            BmsChargeDetail bmsChargeDetail = new BmsChargeDetail();
            bmsChargeDetail.setDeviceId(deviceSn);
            bmsChargeDetail.setTimestamp(frameTime);
            bmsChargeDetail.setAcChargeCurrent(BigDecimal.valueOf(tChgCur));
            bmsChargeDetail.setAcChargeVoltage(BigDecimal.valueOf(tChgVol));
            bmsChargeDetail.setDcChargeCurrent(BigDecimal.valueOf(fChgCur));
            bmsChargeDetail.setDcChargeVoltage(BigDecimal.valueOf(fChgVol));
            bmsChargeDetail.setChargeTime(chgTime);
            bmsChargeDetail.setAcStopCode(acStopCode);
            bmsChargeDetail.setDcStopCode(dcStopCode);
            bmsChargeDetail.setAcCpValue(tChgCp);
            bmsChargeDetail.setAcGunResistance(tChgR);
            bmsChargeDetail.setChargingStage(chgSts);
            bmsChargeDetail.setAcStage(tChgSts);
            bmsChargeDetail.setDcStage(fChgSts2);
            bmsChargeDetail.setCreateTime(new Date());
            bmsChargeDetail.setCreateBy(deviceSn);
            bmsChargeDetailService.insertBmsChargeDetail(bmsChargeDetail);

            BmsRuntimeData rd = new BmsRuntimeData();
            rd.setDeviceId(deviceSn);
            rd.setTimestap(frameTime);
            rd.setVehicleSpeed(BigDecimal.valueOf(carSpd));
            rd.setMileage(mileage);
            rd.setSystemVoltage(BigDecimal.valueOf(sysVol));
            rd.setSystemCurrent(BigDecimal.valueOf(sysCur));
            rd.setInsulationResistance((long) insulationVal);
            rd.setSocMax(BigDecimal.valueOf(realSocMax));
            rd.setSocMin(BigDecimal.valueOf(realSocMin));
            rd.setGpvVoltage(BigDecimal.valueOf(gpv));
            rd.setRunStatus(runSts);
            rd.setPowerStatus(runPwrSts);
            rd.setCreateTime(new Date());
            rd.setCreateBy(deviceSn);
            bmsRuntimeDataService.insertBmsRuntimeData(rd);

            BmsSopData sop = new BmsSopData();
            sop.setDeviceId(deviceSn);
            sop.setTimestap(frameTime);
            sop.setDischargeSop10s(disSop10);
            sop.setDischargeSop30s(disSop30);
            sop.setDischargeSop60s(disSop60);
            sop.setDischargeSopContinuous(disSopCont);
            sop.setRegenSop10s(regSop10);
            sop.setRegenSop30s(regSop30);
            sop.setRegenSop60s(regSop60);
            sop.setRegenSopContinuous(regSopCont);
            sop.setChargeSop(chargeSop);
            sop.setAcChargeSop(acChargeSop);
            sop.setCreateTime(new Date());
            sop.setCreateBy(deviceSn);
            bmsSopDataService.insertBmsSopData(sop);

            BmsSystemStatus ss = new BmsSystemStatus();
            ss.setDeviceId(deviceSn);
            ss.setTimestap(frameTime);
            ss.setRelayStatus((long) relayStatus);
            ss.setOnaaccStatus((long) onaaccStatus);
            ss.setResetCount(resetCount);
            ss.setCycleCount((long) cycleCount);
            ss.setSample25v(BigDecimal.valueOf(samp25v));
            ss.setSample5v(BigDecimal.valueOf(samp5v));
            /*ss.setCellCount(cellCount);
            ss.setTempSensorCount(tempSensorCount);*/
            ss.setCreateTime(new Date());
            ss.setCreateBy(deviceSn);
            bmsSystemStatusService.insertBmsSystemStatus(ss);

            int[] chargeTemps = {chgBs1Tmp, chgBs2Tmp, chgBs3Tmp, chgBs4Tmp, chgBs5Tmp, chgBs6Tmp, chgBs7Tmp, chgBs8Tmp};
            List<BmsChargeTemperature> chargeTempsList = new ArrayList<>();
            for (int i = 0; i < chargeTemps.length; i++) {
                BmsChargeTemperature ct = new BmsChargeTemperature();
                ct.setDeviceId(deviceSn);
                ct.setTimestap(frameTime);
                ct.setTempIndex(i + 1);
                ct.setTemperature(BigDecimal.valueOf(chargeTemps[i]));
                ct.setCreateTime(new Date());
                ct.setCreateBy(deviceSn);
                chargeTempsList.add(ct);
            }
             bmsChargeTemperatureService.saveBatch(chargeTempsList);

            double[] rtpVals = {rtp1, rtp2, rtp3, rtp4, rtp5, rtp6, rtp7};
            List<BmsVoltageChannelData> channels = new ArrayList<>();
            for (int i = 0; i < rtpVals.length; i++) {
                BmsVoltageChannelData ch = new BmsVoltageChannelData();
                ch.setDeviceId(deviceSn);
                ch.setTimestap(frameTime);
                ch.setChannelType("RTP");
                ch.setChannelIndex(i + 1);
                ch.setVoltage(BigDecimal.valueOf(rtpVals[i]));
                ch.setCreateTime(new Date());
                ch.setCreateBy(deviceSn);
                channels.add(ch);
            }
            if (!channels.isEmpty()) {
                bmsVoltageChannelDataService.saveBatch(channels);
            }

            log.info("设备 {} 充电详情: tChgCurA={}, tChgVolV={}, fChgCurA={}, fChgVolV={}, disSOP(A)=[{},{},{},{}], regSOP(A)=[{},{},{},{}], disSopTolA={}, regSopTolA={}", deviceSn, tChgCur, tChgVol, fChgCur, fChgVol, disSop10, disSop30, disSop60, disSopCont, regSop10, regSop30, regSop60, regSopCont, disSopTol, regSopTol);
            log.info("设备 {} 版本与编码: hwVer={}, swVer={}, BMSCode='{}', VIN='{}', clientCode='{}', devId={}", deviceSn, hwVer, swVer, bmsCode, vin, clientCode, devId);
            log.info("设备 {} 系统状态: sysVolV={}, sysCurA={}, cellCount={}, tempSensorCount={}, relayStatus={}, onaaccStatus={}, acStopCode={}, dcStopCode={}, cycleCount={}, samp25V={}, samp5V={}, chargeSopA={}, acChargeSopA={}", deviceSn, sysVol, sysCur, cellCount, tempSensorCount, relayStatus, onaaccStatus, acStopCode, dcStopCode, cycleCount, samp25v, samp5v, chargeSop, acChargeSop);
            log.info("设备 {} 运行阶段: runSts={}, runPwrSts={}, tChgCp={}, tChgR={}, tChgSts={}, fChgSts={}, chgSts={}, chgTimeMin={}, mileage={}", deviceSn, runSts, runPwrSts, tChgCp, tChgR, tChgSts, fChgSts2, chgSts, chgTime, mileage);
        } catch (Exception e) {
            log.error("设备 {} 解析扩展数据时发生错误: {}", deviceSn, e.getMessage());
        }
    }

    /**
     * 读取 ASCII 字符串
     *
     * @param startAbs BatteryData 绝对索引(例如 602 对应 BMS编码起始)
     * @param len      字节长度
     * @param base     530 的映射起点（message 中的 startIndex）
     */
    private String readAsciiRange(byte[] message, int startAbs, int len, int base) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i++) {
            int idx = base + (startAbs - 530) + i;
            if (idx >= 0 && idx < message.length) {
                int b = message[idx] & 0xFF;
                if (b != 0) {
                    sb.append((char) b);
                }
            }
        }
        return sb.toString().trim();
    }

    /**
     * 根据设备唯一编号(deviceCode)查询系统设备表的SN码
     */
    private String lookupDeviceSnByCode(String deviceCode) {
        try {
            BmsDevices query = new BmsDevices();
            query.setDeviceId(deviceCode);
            List<BmsDevices> list = bmsDevicesService.selectBmsDevicesList(query);
            if (list != null && !list.isEmpty()) {
                String sn = list.get(0).getDeviceSn();
                if (sn != null && !sn.isEmpty()) {
                    return sn;
                }
            }
        } catch (Exception e) {
            log.warn("查询设备SN失败: {}", e.getMessage());
        }
        return null;
    }
}
