package cn.iocoder.yudao.module.iot.service.device;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.DeviceConnectionStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.opc.OpcUtils;
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.DeviceStatusEnum;
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.utils.CronExpressionUtils;
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.scheduler.TaskSchedulerManager;
import cn.iocoder.yudao.module.iot.controller.admin.device.utils.DataTypeParseUtil;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*;
import cn.iocoder.yudao.module.iot.controller.admin.devicecontactmodel.vo.DeviceContactModelPageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.mqttdatarecord.vo.MqttDataRecordPageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.deviceattributetype.DeviceAttributeTypeDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodel.DeviceModelDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodelattribute.DeviceModelAttributeDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodelrules.DeviceModelRulesDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.deviceoperationrecord.DeviceOperationRecordDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicepointrules.DevicePointRulesDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.gateway.GatewayDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.mqttdatarecord.MqttDataRecordDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicecontactmodel.DeviceContactModelDO;
import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.deviceattributetype.DeviceAttributeTypeMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.devicemodel.DeviceModelMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.devicemodelattribute.DeviceModelAttributeMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.devicemodelrules.DeviceModelRulesMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.deviceoperationrecord.DeviceOperationRecordMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.devicepointrules.DevicePointRulesMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.gateway.GatewayMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.mqttdatarecord.MqttDataRecordMapper;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceAttributeDO;
import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceAttributeMapper;

import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IMqttservice;
import cn.iocoder.yudao.module.iot.service.gateway.GatewayService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;

/**
 * 物联设备 Service 实现类
 *
 * @author 内蒙必硕
 */
@Service
@Validated
@Slf4j
public class DeviceServiceImpl implements DeviceService {

    @Resource
    private DeviceMapper deviceMapper;
    @Resource
    private DeviceAttributeMapper deviceAttributeMapper;

    @Resource
    private DeviceModelMapper deviceModelMapper;


    @Resource
    private DeviceModelAttributeMapper deviceModelAttributeMapper;

    @Resource
    private DeviceContactModelMapper deviceContactModelMapper;

    @Resource
    private MqttDataRecordMapper mqttDataRecordMapper;
    @Resource
    @Qualifier("tdengineJdbcTemplate")
    private JdbcTemplate tdengineJdbcTemplate;

    @Resource
    private TDengineService tdengineService;

    @Resource
    private DeviceAttributeTypeMapper deviceAttributeTypeMapper;

    @Resource
    private TaskSchedulerManager taskSchedulerManager;

    @Resource
    private DeviceModelRulesMapper deviceModelRulesMapper;

    @Resource
    private DevicePointRulesMapper devicePointRulesMapper;

    @Resource
    private DeviceOperationRecordMapper deviceOperationRecordMapper;

    @Resource
    private IMqttservice mqttService;

//    @Resource
//    private GatewayService gatewayService;

    @Resource
    private GatewayMapper gatewayMapper;



    @Override
//    @Transactional(rollbackFor = Exception.class)
    public DeviceDO createDevice(DeviceSaveReqVO createReqVO) {
//        if(StringUtils.isNotBlank(createReqVO.getReadTopic())){
//            DeviceDO temp = deviceMapper.selectByTopic(createReqVO.getReadTopic());
//            if (temp!=null){
//                throw exception(DEVICE_EXISTS);
//            }
//        }

        //判断编码是否唯一
        boolean exists = deviceMapper.exists(
                Wrappers.<DeviceDO>lambdaQuery()
                        .eq(DeviceDO::getDeviceCode, createReqVO.getDeviceCode()));

        if (exists) {
            throw exception(DEVICE_CODE_ALREADY_EXISTS);
        }


        DeviceModelDO deviceModelDO = deviceModelMapper.selectById(createReqVO.getDeviceModelId());

        // 插入
        DeviceDO device = BeanUtils.toBean(createReqVO, DeviceDO.class);
        device.setProtocol(deviceModelDO != null ? deviceModelDO.getProtocol() : "");
        //租户ID
        device.setTenantId("1");
        deviceMapper.insert(device);


        //新增模板点位
        LambdaQueryWrapper<DeviceModelAttributeDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DeviceModelAttributeDO::getDeviceModelId,createReqVO.getDeviceModelId()).orderByDesc(DeviceModelAttributeDO::getId);
        List<DeviceModelAttributeDO> deviceModelAttributeDOS = deviceModelAttributeMapper.selectList(lambdaQueryWrapper);

        if (deviceModelAttributeDOS.isEmpty()){
            throw exception(DEVICE_MODEL_ATTRIBUTE_NOT_EXISTS);
        }

        List<DeviceContactModelDO> contactModelList = new ArrayList<>();
        for (DeviceModelAttributeDO attributeDO : deviceModelAttributeDOS) {
            DeviceContactModelDO contactModel = new DeviceContactModelDO();
            BeanUtils.copyProperties(attributeDO, contactModel);
            contactModel.setId(null);
            contactModel.setDeviceId(device.getId());
            contactModel.setCreateTime(LocalDateTime.now());
            contactModel.setUpdateTime(LocalDateTime.now());
            contactModelList.add(contactModel);
        }
        deviceContactModelMapper.insertBatch(contactModelList);

        //创建时序数据库
//        createTDengine(device.getId());

        //新增规则点位
        addNewRulePoints(createReqVO.getDeviceModelId(),device.getId());
        tdengineService.createTdengineTable(device.getId(),contactModelList);

        return device;
    }

    private void addNewRulePoints(Long deviceModelId,Long deviceId) {

        List<DevicePointRulesDO> devicePointRulesDOList = new ArrayList<>();
        DeviceModelDO deviceModelDO = deviceModelMapper.selectById(deviceModelId);
        if(deviceModelDO == null){
            return;
        }
        List<DeviceModelRulesDO> deviceModelRulesDOList = deviceModelRulesMapper.selectList(Wrappers.<DeviceModelRulesDO>lambdaQuery()
                .eq(DeviceModelRulesDO::getModelId, deviceModelDO.getId()));

        for (DeviceModelRulesDO deviceModelRulesDO : deviceModelRulesDOList) {
            DevicePointRulesDO devicePointRulesDO = new DevicePointRulesDO();
            BeanUtils.copyProperties(deviceModelRulesDO, devicePointRulesDO);
            devicePointRulesDO.setId(null);
            devicePointRulesDO.setDeviceId(deviceId);
            devicePointRulesDOList.add(devicePointRulesDO);
        }
        devicePointRulesMapper.insertBatch(devicePointRulesDOList);
    }

    //@Scheduled(cron="0/5 * *  * * ? ")   //每1秒执行一次
    public void updateDeviceStatus(){
        List<DeviceDO> list = deviceMapper.selectList();
        MqttDataRecordPageReqVO reqVO = new MqttDataRecordPageReqVO();
        LocalDateTime[] dateTimes= {LocalDateTime.now().plusSeconds(-5),LocalDateTime.now()};
        reqVO.setCreateTime(dateTimes);
        reqVO.setPageSize(1);
        for (DeviceDO deviceDO : list) {
            reqVO.setDeviceName(deviceDO.getDeviceName());
            List<MqttDataRecordDO> recordDOList = mqttDataRecordMapper.select(reqVO);
            if (recordDOList != null && deviceDO.getStatus().equals("2")) {
                System.out.println(recordDOList);
                deviceDO.setStatus("1");
                deviceMapper.updateById(deviceDO);
            }else if ((recordDOList == null|| recordDOList.size()==0) && deviceDO.getStatus().equals("1")){
                deviceDO.setStatus("2");
                deviceMapper.updateById(deviceDO);
            }
        }
    }

    @Override
    public void updateDevice(DeviceSaveReqVO updateReqVO) {
        // 校验存在
        validateDeviceExists(updateReqVO.getId());
        //校驗topic是否唯一
        validTopicExists(updateReqVO.getTopic());

        // 更新
        DeviceDO updateObj = BeanUtils.toBean(updateReqVO, DeviceDO.class);
        deviceMapper.updateById(updateObj);
    }

    private void validTopicExists(String topic) {
        boolean exists = deviceMapper.exists(Wrappers.<DeviceDO>lambdaQuery().eq(DeviceDO::getTopic, topic));
        if (exists){
            throw exception(DEVICE_MQTT_TOPIC_ALREADY_EXIST);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDevice(List<Long> ids) {
        for (Long id : ids) {
            // 校验存在
            validateDeviceExists(id);
            //是否有引用
            validateReference(id);
//            // 删除
//            deviceMapper.deleteById(id);
            // 删除子表
            deleteDeviceConcatByDeviceId(id);

        }
        deviceMapper.deleteByIds(ids);
    }

    private void validateReference(Long deviceId) {

        int count = deviceMapper.selectIsReference(deviceId);
        if (count > 0){
            throw exception(DEVICE_REFERENCES_EXIST);
        }

    }

    private void deleteDeviceConcatByDeviceId(Long id) {
        LambdaQueryWrapper<DeviceContactModelDO> deviceContactModelDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        deviceContactModelDOLambdaQueryWrapper.eq(DeviceContactModelDO::getDeviceId,id);
        deviceContactModelMapper.delete(deviceContactModelDOLambdaQueryWrapper);
    }

    private void validateDeviceExists(Long id) {
        if (deviceMapper.selectById(id) == null) {
            throw exception(DEVICE_NOT_EXISTS);
        }
    }

    @Override
    public DeviceRespVO getDevice(Long id) {
        DeviceDO deviceDO = deviceMapper.selectById(id);
        DeviceRespVO deviceRespVO = BeanUtils.toBean(deviceDO, DeviceRespVO.class);
        List<DevicePointRulesDO> devicePointRulesDOList = devicePointRulesMapper.selectList(Wrappers.<DevicePointRulesDO>lambdaQuery()
                .eq(DevicePointRulesDO::getDeviceId, id));
//
//        //设置点位规则
//        if (!devicePointRulesDOList.isEmpty()){
//
//            deviceRespVO.setPointRulesVOList(devicePointRulesDOList);
//        }

        return deviceRespVO;

    }
    @Override
    public DeviceDO getDeviceByName(String name) {
        return deviceMapper.selectByName(name);
    }
    @Override
    public DeviceDO getDeviceByTopic(String topic) {
        return deviceMapper.selectByTopic(topic);
    }
    @Override
    public PageResult<DeviceRespVO> getDevicePage(DevicePageReqVO pageReqVO) {

        // 1. 查询分页设备
        PageResult<DeviceDO> deviceDOPageResult = deviceMapper.selectPage(pageReqVO);
        List<Long> deviceIds = deviceDOPageResult.getList().stream()
                .map(DeviceDO::getId)
                .collect(Collectors.toList());

        // 2. 批量获取 TDengine 最新 ts
        Map<Long, LocalDateTime> latestTsMap = tdengineService.newSelectLatestTsBatch(deviceIds);

        // 3. 批量获取最新的 DeviceOperationRecord
        List<String> ruleCodes = Arrays.stream(DeviceStatusEnum.values())
                .map(DeviceStatusEnum::getCode)
                .collect(Collectors.toList());

        List<DeviceOperationRecordDO> operationRecords = deviceOperationRecordMapper.selectList(
                Wrappers.<DeviceOperationRecordDO>lambdaQuery()
                        .in(DeviceOperationRecordDO::getDeviceId, deviceIds)
                        .in(DeviceOperationRecordDO::getRule, ruleCodes)
                        .orderByDesc(DeviceOperationRecordDO::getCreateTime)
        );

        // 按 deviceId 分组，取最新一条
        Map<Long, DeviceOperationRecordDO> latestRecordMap = operationRecords.stream()
                .collect(Collectors.toMap(
                        DeviceOperationRecordDO::getDeviceId,
                        r -> r,
                        (r1, r2) -> r1.getCreateTime().isAfter(r2.getCreateTime()) ? r1 : r2
                ));

        // 4. 转换分页 DTO
        PageResult<DeviceRespVO> deviceRespVOPageResult = BeanUtils.toBean(deviceDOPageResult, DeviceRespVO.class);

        for (DeviceRespVO deviceRespVO : deviceRespVOPageResult.getList()) {
            Long deviceId = deviceRespVO.getId();

            // 设置最新 ts
            if(latestTsMap.get(deviceId) != null){
                deviceRespVO.setCollectionTime(latestTsMap.get(deviceId));

            }

            // 设置运行状态
            DeviceOperationRecordDO record = latestRecordMap.get(deviceId);
            if (record != null) {
                deviceRespVO.setOperatingStatus(DeviceStatusEnum.getByCode(record.getRule()).getName());
            } else {
                deviceRespVO.setOperatingStatus(DeviceStatusEnum.OFFLINE.getName());

            }


        }

        return deviceRespVOPageResult;
    }

    @Override
    public List<DeviceDO> selectList(DevicePageReqVO reqVO){
        return deviceMapper.selectList(reqVO);
    }
    // ==================== 子表（设备属性） ====================

    @Override
    public PageResult<DeviceContactModelDO> getDeviceAttributePage(PageParam pageReqVO, DeviceContactModelPageReqVO deviceModelAttributePageReqVO) {
        // 参数校验
        if (deviceModelAttributePageReqVO.getDeviceId() == null) {
            throw exception(DEVICE_ID_MODEL_NOT_EXISTS);

        }

        // 查询设备信息，只查询一次
        DeviceDO device = deviceMapper.selectById(deviceModelAttributePageReqVO.getDeviceId());
        if (device == null) {
            return new PageResult<>();
        }
        deviceModelAttributePageReqVO.setDeviceId(device.getId());
        // 判断设备模型ID是否有效
        PageResult<DeviceContactModelDO> deviceModelAttributeDOPageResult = deviceContactModelMapper.selectPageById(pageReqVO, deviceModelAttributePageReqVO);


//        Map<Long, Map<String, Object>> deviceDataMap = createDeviceDataMap(device.getId());

        //获取td数据库最新一条数据
        Map<String, Object> latestRow  = tdengineService.newSelectLatestRow(device.getId());


        List<DeviceContactModelDO> records = deviceModelAttributeDOPageResult.getList();

        if (latestRow != null && !latestRow.isEmpty()) {

            // 1. 取 ts 时间
            Object tsObj = latestRow.get("ts");
            String latestTime = null;

            if (tsObj instanceof Timestamp) {
                latestTime = ((Timestamp) tsObj).toLocalDateTime().toString();
            } else if (tsObj instanceof LocalDateTime) {
                latestTime = tsObj.toString();
            } else if (tsObj != null) {
                latestTime = tsObj.toString();
            }


            // 2. 遍历 records，匹配列名（attributeCode）
            for (DeviceContactModelDO record : records) {

                String attributeCode = record.getAttributeCode();

                if (attributeCode == null) {
                    continue;
                }

                // 从 latestRow 获取对应列值
                Object rawValue = latestRow.get(attributeCode);

                if (rawValue == null) {
                    continue;
                }

                // 根据 dataType 解析
                Object parsedValue = DataTypeParseUtil.parse(rawValue, record.getDataType());

                // 按比例调整
                Object finalValue = adjustByRatio(parsedValue, record.getRatio());

                // 设置值
                record.setAddressValue(finalValue);

                // 使用最新 ts 设置最新采集时间
                record.setLatestCollectionTime(latestTime);
            }

        }

//            // 合并数据：将 deviceDataMap 的值赋给分页结果中的对应记录
//        List<DeviceContactModelDO> records = deviceModelAttributeDOPageResult.getList();
//        for (DeviceContactModelDO record : records) {
//            Map<String, Object> data = deviceDataMap.get(record.getId());
//            if (data != null) {
//                record.setAddressValue(adjustByRatio(data.get("addressValue"), record.getRatio())); // 设置 addressValue
//                record.setLatestCollectionTime((String) data.get("timestamp")); // 设置 latestCollectionTime
//            }
//        }

        return deviceModelAttributeDOPageResult;
    }

    private Object adjustByRatio(Object value, Double ratio) {

        if (value == null) return null;

        try {
            Double result = Double.parseDouble(value.toString());
            return (ratio != null && ratio != 0.0) ? result / ratio : result;
        } catch (NumberFormatException e) {
            return value; // 转换失败返回原值
        }
    }

    @Override
    public Map<Long, Map<String, Object>> createDeviceDataMap(Long deviceId) {
        // 创建结果Map：键为数据记录ID (Long)，值为该条记录的详细信息 (Map<String, Object>)
        Map<Long, Map<String, Object>> resultMap = new HashMap<>();

        // 1. 从TDengine获取设备的最新数据记录
        Map<String, Object> latestDeviceData = tdengineService.getLatestDeviceData(deviceId);
        if (latestDeviceData == null) {
            return resultMap; // 如果没有数据，返回空Map
        }

        try {
            // 2. 解析queryData字段中的JSON数组，它包含多条数据记录
            String queryDataJson = (String) latestDeviceData.get("queryData");
            if (queryDataJson != null && !queryDataJson.isEmpty()) {
                List<DeviceContactModelDO> dataRecords = JSON.parseArray(queryDataJson, DeviceContactModelDO.class);

                Timestamp ts = null;
                String formattedTime = null;

                Object timestampObj = latestDeviceData.get("timestamp");
                if (timestampObj != null) {
                    if (timestampObj instanceof Timestamp) {
                        // 如果已经是Timestamp类型，直接转换
                        ts = (Timestamp) timestampObj;
                    } else if (timestampObj instanceof String) {
                        // 如果是String类型，需要解析
                        String timestampStr = (String) timestampObj;
                        try {
                            // 假设字符串是时间戳格式（如：2023-10-01 10:20:30）
                            ts = Timestamp.valueOf(timestampStr);
                        } catch (IllegalArgumentException e) {
                            // 如果格式不正确，尝试其他解析方式
                            System.err.println("时间戳格式不正确: " + timestampStr);
                            // 可以设置默认值或使用当前时间
                            ts = new Timestamp(System.currentTimeMillis());
                        }
                    }

                    if (ts != null) {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        formattedTime = sdf.format(ts);
                    }
                }

                // 4. 遍历每一条数据记录
                for (DeviceContactModelDO record : dataRecords) {
                    // 创建用于存储单条记录详细信息的Map
                    Map<String, Object> recordInfoMap = new HashMap<>();

                    // 4.1 放入记录的基础信息
                    recordInfoMap.put("deviceId", deviceId);      // 设备ID
                    recordInfoMap.put("timestamp", formattedTime); // 时间戳
                    recordInfoMap.put("tableName", "d_" + deviceId); // 源表名

                    // 4.2 放入从JSON记录中解析出的具体数据
                    recordInfoMap.put("addressValue", record.getAddressValue());
                    // 可以根据需要放入其他字段，例如：
                    // recordInfoMap.put("address", record.getAddress());
                    // recordInfoMap.put("name", record.getName());

                    // 5. 关键步骤：以数据记录自身的ID为键，将其详细信息放入结果Map
                    // 这里假设 DeviceContactModelDO 有一个唯一标识的id字段
                    Long recordId = record.getId();
                    if (recordId != null) {
                        resultMap.put(recordId, recordInfoMap);
                    } else {
                        // 如果记录没有ID，可以记录日志或使用其他策略（如生成临时ID），这里简单跳过
                        log.error("发现一条数据记录缺少ID，已跳过");
                    }
                }
            }
        } catch (Exception e) {
            // 异常处理
            log.error("处理设备" + deviceId + "的数据时发生异常: ", e.getMessage());
            return new HashMap<>();
        }

        return resultMap;
    }

    @Override
    public List<DevicePointRespVO> devicePointList() {

        List<DevicePointRespVO> devicePointRespVOList = new ArrayList<>();
        List<DeviceDO> deviceDOS = deviceMapper.selectList(Wrappers.<DeviceDO>lambdaQuery().orderByDesc(DeviceDO::getCreateTime));
        if (deviceDOS.isEmpty()){
            return devicePointRespVOList;
        }
        for (DeviceDO deviceDO : deviceDOS) {
            DevicePointRespVO devicePointRespVO = new DevicePointRespVO();
            devicePointRespVO.setDeviceId(deviceDO.getId());
            devicePointRespVO.setDeviceName(deviceDO.getDeviceName());

            List<DeviceContactModelDO> deviceContactModelDOS = deviceContactModelMapper.selectList(
                    Wrappers.<DeviceContactModelDO>lambdaQuery()
                            .eq(DeviceContactModelDO::getDeviceId, deviceDO.getId()));

            if (!deviceContactModelDOS.isEmpty()){
                devicePointRespVO.setContactModelDOList(deviceContactModelDOS);
            }
            devicePointRespVOList.add(devicePointRespVO);

        }
        return devicePointRespVOList;
    }



    @Override
    public Long createDeviceAttribute(DeviceAttributeDO deviceAttribute) {
        deviceAttributeMapper.insert(deviceAttribute);
        return deviceAttribute.getId();
    }

    @Override
    public void updateDeviceAttribute(DeviceAttributeDO deviceAttribute) {
        // 校验存在
        validateDeviceAttributeExists(deviceAttribute.getId());
        // 更新
        deviceAttributeMapper.updateById(deviceAttribute);
    }

    @Override
    public void deleteDeviceAttribute(Long id) {
        // 校验存在
        validateDeviceAttributeExists(id);
        // 删除
        deviceAttributeMapper.deleteById(id);
    }

    @Override
    public DeviceAttributeDO getDeviceAttribute(Long id) {
        return deviceAttributeMapper.selectById(id);
    }

    @Override
    public Boolean connectDevice(DeviceSaveReqVO createReqVO) {

        // 前置校验
        DeviceDO deviceDO = validateConnectRequest(createReqVO);

        if (Objects.equals(createReqVO.getIsConnect(), DeviceConnectionStatusEnum.CONNECTED.getStatus())){
            boolean connected = OpcUtils.connect(deviceDO.getId(),deviceDO.getUrl(),deviceDO.getUsername(),deviceDO.getPassword(),10);
            if (connected){
                deviceDO.setStatus(String.valueOf(DeviceConnectionStatusEnum.CONNECTED.getStatus()));
                deviceMapper.updateById(deviceDO);

                String cronExpression = CronExpressionUtils.secondsToCron(deviceDO.getSampleCycle());

                taskSchedulerManager.startDeviceTask(
                        deviceDO.getId(),
                        cronExpression
                );


            }else {
                throw exception(OPC_CONNECT_FAILURE_DOES_NOT_EXIST);
            }
        }else if(Objects.equals(createReqVO.getIsConnect(), DeviceConnectionStatusEnum.DISCONNECTED.getStatus())){
            boolean disconnect = OpcUtils.disconnect(deviceDO.getId());
            if (disconnect){
                //更新连接状态
                deviceDO.setStatus(String.valueOf(DeviceConnectionStatusEnum.DISCONNECTED.getStatus()));
                deviceMapper.updateById(deviceDO);
                //停止定时任务
                taskSchedulerManager.stopDeviceTask(deviceDO.getId());
                //更新运行状态
                updateOperationalStatus(deviceDO);



            }else {
                throw exception(OPC_CLOSE_CONNECT_FAILURE);
            }
        }else {
            throw exception(OPC_PARAMETER_DOES_NOT_EXIST);
        }

        return Boolean.TRUE;
    }

    private void updateOperationalStatus(DeviceDO deviceDO) {
        DeviceOperationRecordDO deviceOperationRecordDO = new DeviceOperationRecordDO();
        deviceOperationRecordDO.setDeviceId(deviceDO.getId());
        deviceOperationRecordDO.setRule(DeviceStatusEnum.OFFLINE.getCode());
        deviceOperationRecordMapper.insert(deviceOperationRecordDO);
    }

    private DeviceDO validateConnectRequest(DeviceSaveReqVO createReqVO) {
        if(createReqVO.getId() == null){
            throw exception(DEVICE_ID_DOES_NOT_EXIST);
        }
        DeviceDO deviceDO = deviceMapper.selectById(createReqVO.getId());
        if (deviceDO == null){
            throw exception(DEVICE_DOES_NOT_EXIST);

        }
        if (StringUtils.isBlank(deviceDO.getUrl())){
            throw exception(ENDPOINT_DOES_NOT_EXIS);
        }
        if (StringUtils.isBlank(deviceDO.getUsername())){
            throw exception(OPC_USERNAME_DOES_NOT_EXIST);
        }
        if (StringUtils.isBlank(deviceDO.getPassword())){
            throw exception(OPC_PASSWORD_DOES_NOT_EXIST);
        }
        return  deviceDO;
    }

    @Override
    public Long copyDevice(Long id) {
        if (id == null){
            throw exception(DEVICE_ID_MODEL_NOT_EXISTS);
        }
        DeviceDO deviceDO = deviceMapper.selectById(id);
        if(deviceDO == null){
            throw exception(DEVICE_DOES_NOT_EXIST);
        }
        //复制实体类
        DeviceDO newDevice = new DeviceDO();
        BeanUtils.copyProperties(deviceDO, newDevice);
        newDevice.setId(null);
        Random random = new Random();
        int randomNumber = random.nextInt(9000) + 1000;
        newDevice.setDeviceCode(deviceDO.getDeviceCode()+ "-" + randomNumber);
        newDevice.setDeviceName(deviceDO.getDeviceName() + "-副本");
        deviceMapper.insert(newDevice);

        //复制关联表
        LambdaQueryWrapper<DeviceContactModelDO> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(DeviceContactModelDO::getDeviceId,deviceDO.getId());
        List<DeviceContactModelDO> deviceContactModelDOS = deviceContactModelMapper.selectList(lambdaQueryWrapper);


        if (deviceContactModelDOS != null && !deviceContactModelDOS.isEmpty()){
            for (DeviceContactModelDO deviceModelAttributeDOS : deviceContactModelDOS) {
                deviceModelAttributeDOS.setId(null);
                deviceModelAttributeDOS.setDeviceId(newDevice.getId());
            }
            deviceContactModelMapper.insertBatch(deviceContactModelDOS);
        }

        return newDevice.getId();

    }

    @Override
    public PageResult<LineDeviceRespVO> lineDevicePage(LineDeviceRequestVO pageReqVO) {

        // 1. 查询分页设备
        PageResult<DeviceRespVO> pageResult =
                getDevicePage(BeanUtils.toBean(pageReqVO, DevicePageReqVO.class));

        List<DeviceRespVO> deviceList =
                Optional.ofNullable(pageResult.getList())
                        .orElse(Collections.emptyList());

        if (deviceList.isEmpty()) {
            return PageResult.empty();
        }



        // 2. 提取 deviceIds
        List<Long> deviceIds =
                deviceList.stream()
                        .map(DeviceRespVO::getId)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());

//        // 批量查 workshop
//        List<Map<String,Object>> mapList = deviceMapper.selectWorkshopBatch(deviceIds);
//
//        Map<Long, String> workshopMap = mapList.stream()
//                .filter(m -> m.get("deviceId") != null) // 避免 deviceId null
//                .collect(Collectors.toMap(
//                        m -> ((Number) m.get("deviceId")).longValue(),
//                        m -> m.get("workshop") != null ? m.get("workshop").toString() : "",
//                        (existing, replacement) -> replacement
//                ));

        // 3. 批量查询最新采集时间（TDengine）
        Map<Long, LocalDateTime> latestTsMap =
                tdengineService.newSelectLatestTsBatch(deviceIds);

        // 4. 时间格式化器
        DateTimeFormatter formatter =
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 5. 转换结果（使用 stream 更简洁）
        List<LineDeviceRespVO> list =
                deviceList.stream()
                        .map(device -> {

                            LineDeviceRespVO vo = new LineDeviceRespVO();

                            vo.setId(device.getId());
                            vo.setDeviceCode(device.getDeviceCode());
                            vo.setDeviceName(device.getDeviceName());
                            vo.setStatus(device.getStatus());

                            // 优先使用 TDengine 最新时间
                            LocalDateTime latestTs =
                                    latestTsMap.get(device.getId());

                            if (latestTs != null) {
                                vo.setCollectionTime(latestTs.format(formatter));
                            } else if (device.getCollectionTime() != null) {
                                vo.setCollectionTime(
                                        device.getCollectionTime()
                                                .format(formatter)
                                );
                            } else {
                                vo.setCollectionTime(null);
                            }

                            // 查询产线名称
                            vo.setLineName(
                                    deviceMapper.lineDeviceLedgerPage(device.getId())
                            );
//                            vo.setLineName(workshopMap.get(device.getId()));


                            return vo;
                        })
                        .collect(Collectors.toList());

        // 6. 返回分页结果
        return new PageResult<>(list, pageResult.getTotal());
    }


    @Override
    public List<LineDeviceRespVO> lineDeviceList(LineDeviceRequestVO pageReqVO) {

        List<LineDeviceRespVO> records = deviceMapper.lineDeviceList(pageReqVO);
        if (records.isEmpty()) {
            return records;
        }

        // 1. 收集所有设备ID
        List<Long> deviceIds = records.stream()
                .map(LineDeviceRespVO::getDeviceId)
                .collect(Collectors.toList());

        // 2. 批量查询每个设备的最新时间
        Map<Long, LocalDateTime> latestTsMap = tdengineService.newSelectLatestTsBatch(deviceIds);

        // 3. 填充 collectionTime
        for (LineDeviceRespVO record : records) {
            LocalDateTime ts = latestTsMap.get(record.getDeviceId());
            if (ts != null) {
                record.setCollectionTime(ts.toString()); // 或 formatDateTime(ts) 根据你的需求
            }
        }

        return records;

    }

    @Override
    public Map<String, List<Map<String, Object>>> singleDevice(Long deviceId) {

        Map<String, List<Map<String, Object>>> resultMap = new LinkedHashMap<>();

        List<DeviceContactModelDO> records = deviceContactModelMapper.selectList(Wrappers.<DeviceContactModelDO>lambdaQuery()
                                    .eq(DeviceContactModelDO::getDeviceId,deviceId)
                                    .orderByDesc(DeviceContactModelDO::getId));

        if (records == null || records.isEmpty()) {
            return resultMap;
        }

        try {
            // 获取最新一行数据
            Map<String, Object> latestRow = tdengineService.newSelectLatestRow(deviceId);
            if (latestRow == null || latestRow.isEmpty()) {
                return resultMap;
            }

//            // 获取 ts 时间
//            Object tsObj = latestRow.get("ts");
//            String latestTime = tsObj instanceof Timestamp ? ((Timestamp) tsObj).toLocalDateTime().toString()
//                    : tsObj != null ? tsObj.toString() : null;

            // 属性类型映射
            Map<Long, String> idToNameMap = deviceAttributeTypeMapper.selectList()
                    .stream()
                    .collect(Collectors.toMap(
                            DeviceAttributeTypeDO::getId,
                            DeviceAttributeTypeDO::getName
                    ));
            Map<Long, String> attributeTypeCache = new HashMap<>();

            // 遍历 records 填充数据
            for (DeviceContactModelDO record : records) {

                String attributeCode = record.getAttributeCode();
                if (attributeCode == null) continue;

                Object rawValue = latestRow.get(attributeCode);
//                if (rawValue == null) continue;

                Object finalValue = DataTypeParseUtil.parse(rawValue, record.getDataType());
//                Object finalValue = adjustByRatio(finalValueparsedValue, record.getRatio());

                record.setAddressValue(finalValue);
//                record.setLatestCollectionTime(latestTime);

                // 属性类型名称
                String attributeTypeName = "其他";
                Object typeObj = record.getAttributeType();
                if (typeObj != null) {
                    String typeStr = typeObj.toString();
                    try {
                        Long typeId = Long.parseLong(typeStr);
                        attributeTypeName = attributeTypeCache.computeIfAbsent(typeId,
                                k -> idToNameMap.getOrDefault(typeId, typeStr));
                    } catch (NumberFormatException e) {
                        attributeTypeName = typeStr;
                    }
                }

                Map<String, Object> simplifiedData = new HashMap<>();
                simplifiedData.put("addressValue", record.getAddressValue());
                simplifiedData.put("attributeName", record.getAttributeName());

                resultMap.computeIfAbsent(attributeTypeName, k -> new ArrayList<>()).add(simplifiedData);
            }

        } catch (Exception e) {
            log.warn("处理设备 {} 最新数据时异常: {}", deviceId, e.getMessage());
        }

        return resultMap;
    }


    @Override
    public PageResult<Map<String, Object>> historyRecord(
            Long deviceId,
            String collectionStartTime,
            String collectionEndTime,
            Integer page,
            Integer pageSize) {

        List<Map<String, Object>> resultList = new ArrayList<>();

        if (deviceId == null) {
            return PageResult.empty();
        }

        try {

            // 1. 查询TDengine分页数据
            List<Map<String, Object>> deviceDataList =
                    tdengineService.newSelectBatchPage(
                            deviceId,
                            collectionStartTime,
                            collectionEndTime,
                            page,
                            pageSize
                    );

            long total =
                    tdengineService.newSelectBatchTotal(
                            deviceId,
                            collectionStartTime,
                            collectionEndTime
                    );

            if (deviceDataList.isEmpty()) {
                return new PageResult<>(resultList, total);
            }

            // 2. 查询属性配置（完整字段来源）
            List<DeviceContactModelDO> attributeList =
                    deviceContactModelMapper.selectList(
                            Wrappers.lambdaQuery(DeviceContactModelDO.class)
                                    .eq(DeviceContactModelDO::getDeviceId, deviceId)
                                    .orderByAsc(DeviceContactModelDO::getSort)
                    );

            // 时间格式化器
            DateTimeFormatter formatter =
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

            // 3. 遍历TDengine数据
            for (Map<String, Object> row : deviceDataList) {

                Object tsObj = row.get("ts");

                if (tsObj == null) {
                    continue;
                }

                // 格式化时间
                String collectTime;

                if (tsObj instanceof LocalDateTime) {

                    collectTime =
                            ((LocalDateTime) tsObj)
                                    .format(formatter);

                } else if (tsObj instanceof Timestamp) {

                    collectTime =
                            ((Timestamp) tsObj)
                                    .toLocalDateTime()
                                    .format(formatter);

                } else {

                    collectTime = tsObj.toString();
                }

                // 按 typeName 分组
                Map<String, List<Map<String, Object>>> groupedData =
                        new LinkedHashMap<>();

                // 核心逻辑：遍历 attributeList（保证全部字段返回）
                for (DeviceContactModelDO attribute : attributeList) {

                    String column =
                            attribute.getAttributeCode();

                    Object rawValue =
                            row.get(column);

                    // 使用 typeName 分组（核心优化点）
                    String typeName =
                            attribute.getTypeName();

                    if (typeName == null || typeName.isEmpty()) {
                        typeName = "其他";
                    }

                    Map<String, Object> simplifiedData =
                            new HashMap<>();

                    simplifiedData.put(
                            "addressValue",
                            rawValue != null
                                    ? rawValue.toString()
                                    : null
                    );

                    simplifiedData.put(
                            "attributeName",
                            attribute.getAttributeName()
                    );

                    groupedData
                            .computeIfAbsent(
                                    typeName,
                                    k -> new ArrayList<>()
                            )
                            .add(simplifiedData);
                }

                // 构建最终结构（保持旧结构完全一致）
                Map<String, Object> timePointData =
                        new LinkedHashMap<>(groupedData);

                timePointData.put(
                        "collectTime",
                        collectTime
                );

                resultList.add(timePointData);
            }

            return new PageResult<>(resultList, total);

        } catch (Exception e) {

            log.error("处理设备历史数据异常", e);

            return PageResult.empty();
        }
    }







    private void validateDeviceAttributeExists(Long id) {
        if (deviceAttributeMapper.selectById(id) == null) {
            throw exception(DEVICE_ATTRIBUTE_NOT_EXISTS);
        }
    }

    private void deleteDeviceAttributeByDeviceId(Long deviceId) {
        deviceAttributeMapper.deleteByDeviceId(deviceId);
    }

    @Override
    public List<DeviceDO> getList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return deviceMapper.selectBatchIds(ids);
    }




    @Override
    public Boolean scheduledStart(Long id) {
        try {

            // 1. 查询设备信息
            DeviceDO deviceDO = deviceMapper.selectById(id);
            if (deviceDO==null) {
                throw new RuntimeException("设备不存在");
            }
            if (deviceDO.getSampleCycle() == null) {
                throw new RuntimeException("设备cron表达式为空");
            }

            String cronExpression = CronExpressionUtils.secondsToCron(deviceDO.getSampleCycle());

            // 2. 启动定时任务
            boolean success = taskSchedulerManager.startDeviceTask(
                    deviceDO.getId(),
                    cronExpression
            );

            if (!success) {
                throw new RuntimeException("启动定时任务失败");
            }

            return true;

        } catch (Exception e) {
            throw new RuntimeException("连接设备失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Boolean scheduledStop(Long id) {
        try {
            // 1. 停止定时任务
            taskSchedulerManager.stopDeviceTask(id);

            return true;

        } catch (Exception e) {
            throw new RuntimeException("断开设备失败: " + e.getMessage(), e);
        }
    }

    @Override
    public DeviceOperationStatusRespVO getDeviceOperationalStatus() {

        DeviceOperationStatusRespVO deviceOperationalStatus= deviceMapper.getDeviceOperationalStatus();

        // 计算利用率
        calculateUtilizationRate(deviceOperationalStatus);

        // 计算故障率
        calculateFaultRate(deviceOperationalStatus);

        return deviceOperationalStatus;
    }


    /**
     * 计算利用率
     * 利用率 = 运行数量 / 设备总数 * 100%
     */
    private void calculateUtilizationRate(DeviceOperationStatusRespVO statusVO) {
        int totalDevices = statusVO.getTotalDevices();
        int runningCount = statusVO.getRunningCount();

        double utilizationRate = 0.0;
        if (totalDevices > 0) {
            utilizationRate = (double) runningCount / totalDevices * 100;
        }

        // 格式化百分比，保留2位小数
        String formattedRate = String.format("%.2f%%", utilizationRate);
        statusVO.setUtilizationRate(formattedRate);
    }

    /**
     * 计算故障率
     * 故障率 = 故障数量 / 设备总数 * 100%
     */
    private void calculateFaultRate(DeviceOperationStatusRespVO statusVO) {
        int totalDevices = statusVO.getTotalDevices();
        int faultCount = statusVO.getFaultCount();

        double faultRate = 0.0;
        if (totalDevices > 0) {
            faultRate = (double) faultCount / totalDevices * 100;
        }

        // 格式化百分比，保留2位小数
        String formattedRate = String.format("%.2f%%", faultRate);
        statusVO.setFaultRate(formattedRate);
    }

    @Override
    public List<Map<String, Object>> getMultiDeviceAttributes(Long goviewId) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            // 直接从数据库查询deviceIds JSON字符串
            String deviceIdsJson = deviceMapper.selectDeviceIdsByGoviewId(goviewId);
            if (StringUtils.isBlank(deviceIdsJson)) {
                log.info("No deviceIds found for goviewId: {}", goviewId);
                return result;
            }

            // 解析JSON格式的deviceIds
            Map<Long, Set<Long>> deviceAttributeMap = parseDeviceIdsJson(deviceIdsJson);
            if (deviceAttributeMap.isEmpty()) {
                log.warn("No valid device-attribute mapping found for goviewId: {}", goviewId);
                return result;
            }

            // 批量获取所有设备的最新运行记录，减少数据库查询次数
            Map<Long, DeviceOperationRecordDO> latestRecordMap = getLatestDeviceOperationRecords(deviceAttributeMap.keySet());

            log.info("Found {} devices with attribute mappings for goviewId {}: {}",
                    deviceAttributeMap.size(), goviewId, deviceAttributeMap);

            // 遍历每个设备ID，获取设备属性数据
            for (Map.Entry<Long, Set<Long>> entry : deviceAttributeMap.entrySet()) {
                Long deviceId = entry.getKey();
                Set<Long> attributeIds = entry.getValue();

                try {
                    // 获取设备信息
                    DeviceDO device = deviceMapper.selectById(deviceId);
                    if (device == null) {
                        log.warn("Device not found for ID: {}", deviceId);
                        continue;
                    }

                    // 创建设备层级的Map
                    Map<String, Object> deviceMap = new HashMap<>();
                    deviceMap.put("deviceId", deviceId);
                    deviceMap.put("deviceName", device.getDeviceName());
                    deviceMap.put("deviceCode", device.getDeviceCode());

                    // 添加设备运行状态
                    String operatingStatus = getDeviceOperatingStatus(deviceId, latestRecordMap);
                    deviceMap.put("operatingStatus", operatingStatus);

                    // 获取设备属性列表，只查询指定的属性ID
                    List<DeviceContactModelDO> attributes = deviceContactModelMapper.selectList(
                            Wrappers.<DeviceContactModelDO>lambdaQuery()
                                    .eq(DeviceContactModelDO::getDeviceId, deviceId)
                                    .in(DeviceContactModelDO::getId, attributeIds));

                    // 获取设备最新数据
                    Map<Long, Map<String, Object>> deviceDataMap = createDeviceDataMap(deviceId);

                    // 创建属性集合
                    List<Map<String, Object>> attributeList = new ArrayList<>();
                    for (DeviceContactModelDO attribute : attributes) {
                        Map<String, Object> attributeData = new HashMap<>();
                        attributeData.put("attributeId", attribute.getId());
                        attributeData.put("attributeName", attribute.getAttributeName());
                        attributeData.put("attributeCode", attribute.getAttributeCode());
                        attributeData.put("dataType", attribute.getDataType());
                        attributeData.put("dataUnit", attribute.getDataUnit());

                        // 获取最新数据
                        Map<String, Object> latestData = deviceDataMap.get(attribute.getId());
                        if (latestData != null) {
                            attributeData.put("addressValue", adjustByRatio(latestData.get("addressValue"), attribute.getRatio()));
                            attributeData.put("latestCollectionTime", latestData.get("timestamp"));
                        }

                        attributeList.add(attributeData);
                    }

                    // 将属性集合添加到设备层级
                    deviceMap.put("attributes", attributeList);

                    // 添加到结果列表
                    result.add(deviceMap);
                } catch (Exception e) {
                    log.error("Error processing device ID: {} with attributes: {}", deviceId, attributeIds, e);
                    // 继续处理其他设备，不中断整体流程
                }
            }
        } catch (Exception e) {
            log.error("Failed to get multi-device attributes by goviewId: {}", goviewId, e);
        }

        return result;
    }

    /**
     * 获取设备运行状态
     * @param deviceId 设备ID
     * @param latestRecordMap 设备ID到最新运行记录的映射
     * @return 设备运行状态名称
     */
    private String getDeviceOperatingStatus(Long deviceId, Map<Long, DeviceOperationRecordDO> latestRecordMap) {
        DeviceOperationRecordDO record = latestRecordMap.get(deviceId);
        if (record != null) {
            // 根据运行记录的rule字段获取设备状态
            DeviceStatusEnum statusEnum = DeviceStatusEnum.getByCode(record.getRule());
            return statusEnum != null ? statusEnum.getName() : DeviceStatusEnum.OFFLINE.getName();
        } else {
            // 如果没有运行记录，默认为离线状态
            return DeviceStatusEnum.OFFLINE.getName();
        }
    }

    /**
     * 批量获取设备的最新运行记录
     * @param deviceIds 设备ID集合
     * @return 设备ID到最新运行记录的映射
     */
    private Map<Long, DeviceOperationRecordDO> getLatestDeviceOperationRecords(Set<Long> deviceIds) {
        if (deviceIds.isEmpty()) {
            return Collections.emptyMap();
        }

        // 查询所有设备的最新运行记录
        List<DeviceOperationRecordDO> records = deviceOperationRecordMapper.selectList(
                Wrappers.<DeviceOperationRecordDO>lambdaQuery()
                        .in(DeviceOperationRecordDO::getDeviceId, deviceIds)
                        .orderByDesc(DeviceOperationRecordDO::getCreateTime));

        // 构建设备ID到最新记录的映射
        Map<Long, DeviceOperationRecordDO> latestRecordMap = new HashMap<>();
        for (DeviceOperationRecordDO record : records) {
            // 只保留每个设备的第一条记录（因为已经按创建时间倒序排序）
            if (!latestRecordMap.containsKey(record.getDeviceId())) {
                latestRecordMap.put(record.getDeviceId(), record);
            }
        }

        return latestRecordMap;
    }

    /**
     * 解析JSON格式的deviceIds字符串
     * @param deviceIdsJson JSON格式的设备和属性映射字符串
     * @return 设备ID到属性ID集合的映射（已去重）
     */
    private Map<Long, Set<Long>> parseDeviceIdsJson(String deviceIdsJson) {
        Map<Long, Set<Long>> deviceAttributeMap = new HashMap<>();

        if (StringUtils.isBlank(deviceIdsJson)) {
            return deviceAttributeMap;
        }

        try {
            // 使用Jackson解析JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();
            List<Map<String, Object>> deviceAttributeList = objectMapper.readValue(
                    deviceIdsJson, new TypeReference<List<Map<String, Object>>>() {});

            // 遍历解析结果，构建设备-属性映射并去重
            for (Map<String, Object> item : deviceAttributeList) {
                try {
                    // 提取设备ID
                    Object deviceIdObj = item.get("deviceId");
                    if (deviceIdObj == null) {
                        log.warn("Device ID is null in item: {}", item);
                        continue;
                    }
                    Long deviceId = null;
                    if (deviceIdObj instanceof Number) {
                        deviceId = ((Number) deviceIdObj).longValue();
                    } else {
                        deviceId = Long.parseLong(deviceIdObj.toString());
                    }

                    // 提取属性ID数组
                    List<Long> attributeIds = new ArrayList<>();
                    Object attributesIdsObj = item.get("attributesIds");
                    if (attributesIdsObj instanceof List) {
                        List<?> attributesList = (List<?>) attributesIdsObj;
                        for (Object attrIdObj : attributesList) {
                            if (attrIdObj instanceof Number) {
                                attributeIds.add(((Number) attrIdObj).longValue());
                            } else if (attrIdObj != null) {
                                try {
                                    attributeIds.add(Long.parseLong(attrIdObj.toString()));
                                } catch (NumberFormatException e) {
                                    log.warn("Invalid attribute ID: {}", attrIdObj);
                                }
                            }
                        }
                    }

                    // 合并属性ID到现有设备映射中（避免Lambda变量捕获问题）
                    Set<Long> existingAttributes = deviceAttributeMap.get(deviceId);
                    if (existingAttributes == null) {
                        // 如果设备不存在，创建新的属性集合
                        Set<Long> newAttributesSet = new HashSet<>(attributeIds);
                        deviceAttributeMap.put(deviceId, newAttributesSet);
                    } else {
                        // 如果设备已存在，将新的属性ID添加到现有集合中
                        for (Long attrId : attributeIds) {
                            existingAttributes.add(attrId);
                        }
                    }
                } catch (Exception e) {
                    log.warn("Error parsing device-attribute item: {}", item, e);
                }
            }
        } catch (Exception e) {
            log.error("Error parsing deviceIds JSON: {}", deviceIdsJson, e);
        }

        return deviceAttributeMap;
    }

    @Override
    public List<DeviceContactModelDO> getDeviceAttributeList(Long deviceId) {
        return deviceContactModelMapper.selectList(Wrappers.<DeviceContactModelDO>lambdaQuery()
                .eq(DeviceContactModelDO::getDeviceId,deviceId)
                .orderByDesc(DeviceContactModelDO::getId));
    }

    @Override
    public void updateDeviceEnabled(DeviceUpdateEnabledReqVO updateEnabledReqVO) throws MqttException {

        // 1. 校验任务是否存在
        DeviceDO deviceDO = deviceMapper.selectById(updateEnabledReqVO.getId());
        if (deviceDO == null) {
            throw exception(DEVICE_NOT_EXISTS);
        }
        if (StringUtils.isBlank(deviceDO.getTopic())) {
            throw exception(DEVICE_MQTT_TOPIC_EXIST);
        }

        //TODO 待优化
        if (!"MQTT".equals(deviceDO.getProtocol())) {
            throw exception(DEVICE_MQTT_TOPIC_EXIST);
        }

        // 2. 如果状态没有变化，直接返回
        if (Objects.equals(deviceDO.getIsEnable(), updateEnabledReqVO.getEnabled())) {
            return;
        }

        // 3. 执行状态更新操作
        executeEnableUpdate(deviceDO, updateEnabledReqVO.getEnabled());



    }

    @Override
    public DeviceDO getDeviceByMqttTopic(String topic) {
        return deviceMapper.selectOne(Wrappers.<DeviceDO>lambdaQuery().eq(DeviceDO::getTopic,topic));
    }

    private void executeEnableUpdate(DeviceDO deviceDO, Boolean enabled) {

        try {
            // 1. 更新设备启用状态
            deviceDO.setIsEnable(enabled);
            deviceMapper.updateById(deviceDO);

            String topic = deviceDO.getTopic();

            // 2. 启用设备
            if (enabled) {

                // 2.1 MQTT订阅
                try {
                    mqttService.subscribeTopic(topic);
                    log.info("MQTT订阅成功: {}", topic);
                } catch (MqttException e) {
                    log.error("MQTT订阅失败: {}", topic, e);
                }

                // 2.2 保存到iot_gateway表-用于重启后自动订阅
                GatewayDO gateway = gatewayMapper.selectOne(
                        new LambdaQueryWrapper<GatewayDO>()
                                .eq(GatewayDO::getTopic, topic)
                                .last("LIMIT 1")
                );

                if (gateway == null) {

                    gateway = new GatewayDO();
                    gateway.setGatewayName(deviceDO.getDeviceName());
                    gateway.setGatewayCode(deviceDO.getDeviceCode());
                    gateway.setTopic(topic);
                    gateway.setIsEnable(true);
                    gateway.setDeleted(false);

                    gatewayMapper.insert(gateway);

                    log.info("新增gateway订阅记录成功 topic={}", topic);

                } else {
                    //更新gateway状态
                    gateway.setIsEnable(true);
                    gateway.setUpdateTime(LocalDateTime.now());

                    gatewayMapper.updateById(gateway);
                    log.info("更新gateway启用状态 topic={}", topic);

                }

            }

            // 3. 禁用设备
            else {

                // 3.1 MQTT取消订阅
                try {
                    mqttService.unsubscribeTopic(topic);
                    log.info("MQTT取消订阅成功: {}", topic);
                } catch (MqttException e) {
                    log.error("MQTT取消订阅失败: {}", topic, e);
                }

                // 3.2 更新gateway状态为禁用
                gatewayMapper.update(
                        null,
                        new LambdaUpdateWrapper<GatewayDO>()
                                .eq(GatewayDO::getTopic, topic)
                                .set(GatewayDO::getIsEnable, false)
                                .set(GatewayDO::getUpdateTime, LocalDateTime.now())
                );

                log.info("gateway订阅记录已禁用 topic={}", topic);

                //更新设备运行状态为离线
                updateOperationalStatus(deviceDO);
                log.info("更新设备运行状态为离线 deviceId={}", deviceDO.getId());


            }

        } catch (Exception e) {

            log.error("更新设备状态失败 deviceCode={}", deviceDO.getDeviceCode(), e);

        }
        }



    @Override
    public List<Long> deviceLedgerList() {
        return deviceMapper.deviceLedgerList();
    }

}