package org.dromara.ems.record.service.impl;

import org.dromara.common.core.utils.DateUtils;
import cn.hutool.core.util.ObjectUtil;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.ems.base.mapper.EmsBaseEnergyTypeMapper;
import org.dromara.ems.base.mapper.EmsBaseMonitorInfoMapper;
import org.dromara.ems.record.domain.EmsRecordAlarmData;
import org.dromara.ems.record.domain.EmsRecordAlarmRule;
import org.dromara.ems.record.domain.RecordIotenvInstant;
import org.dromara.ems.record.mapper.EmsRecordAlarmDataMapper;
import org.dromara.ems.record.mapper.EmsRecordAlarmRuleMapper;
import org.dromara.ems.record.mapper.RecordIotenvInstantMapper;
import org.dromara.ems.record.service.IEmsRecordAlarmDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

import static org.dromara.common.satoken.utils.LoginHelper.getUsername;

/**
 * 异常数据记录Service业务层处理
 *
 * @author Yinq
 * @date 2024-05-15
 */
@Service
@RequiredArgsConstructor
public class EmsRecordAlarmDataServiceImpl implements IEmsRecordAlarmDataService {
    
    private final EmsRecordAlarmDataMapper emsRecordAlarmDataMapper;

    
    private final EmsRecordAlarmRuleMapper emsRecordAlarmRuleMapper;

    
    private final RecordIotenvInstantMapper recordIotenvInstantMapper;

    
    private final EmsBaseMonitorInfoMapper emsBaseMonitorInfoMapper;

    
    private final EmsBaseEnergyTypeMapper emsBaseEnergyTypeMapper;

    /**
     * 监测字段字典映射
     * 将前端字典值映射到数据库字段名和中文描述
     */
    private static final Map<Long, String> MONITOR_FIELD_TO_DB_FIELD = new HashMap<>();
    private static final Map<Long, String> MONITOR_FIELD_TO_DESC = new HashMap<>();
    
    static {
        // 字典值 -> 数据库字段名映射
        MONITOR_FIELD_TO_DB_FIELD.put(0L, "temperature");           // 温度
        MONITOR_FIELD_TO_DB_FIELD.put(1L, "humidity");              // 湿度
        MONITOR_FIELD_TO_DB_FIELD.put(2L, "vibration_speed");       // 振动-速度(mm/s)
        MONITOR_FIELD_TO_DB_FIELD.put(3L, "vibration_displacement"); // 振动-位移(um)
        MONITOR_FIELD_TO_DB_FIELD.put(4L, "vibration_acceleration"); // 振动-加速度(g)
        MONITOR_FIELD_TO_DB_FIELD.put(5L, "vibration_temp");        // 振动-温度(℃)
        MONITOR_FIELD_TO_DB_FIELD.put(6L, "noise");                 // 噪音
        MONITOR_FIELD_TO_DB_FIELD.put(7L, "illuminance");           // 照度
        MONITOR_FIELD_TO_DB_FIELD.put(8L, "concentration");         // 气体浓度
        
        // 字典值 -> 中文描述映射（用于异常记录的cause字段）
        MONITOR_FIELD_TO_DESC.put(0L, "温度");
        MONITOR_FIELD_TO_DESC.put(1L, "湿度");
        MONITOR_FIELD_TO_DESC.put(2L, "振动-速度(mm/s)");
        MONITOR_FIELD_TO_DESC.put(3L, "振动-位移(um)");
        MONITOR_FIELD_TO_DESC.put(4L, "振动-加速度(g)");
        MONITOR_FIELD_TO_DESC.put(5L, "振动-温度(℃)");
        MONITOR_FIELD_TO_DESC.put(6L, "噪音");
        MONITOR_FIELD_TO_DESC.put(7L, "照度");
        MONITOR_FIELD_TO_DESC.put(8L, "气体浓度");
    }

    /**
     * 查询异常数据记录
     *
     * @param objId 异常数据记录主键
     * @return 异常数据记录
     */
    @Override
    public EmsRecordAlarmData selectEmsRecordAlarmDataByObjId(Long objId) {
        return emsRecordAlarmDataMapper.selectEmsRecordAlarmDataByObjId(objId);
    }

    /**
     * 查询异常数据记录列表
     *
     * @param emsRecordAlarmData 异常数据记录
     * @return 异常数据记录
     */
    @Override
    public List<EmsRecordAlarmData> selectEmsRecordAlarmDataList(EmsRecordAlarmData emsRecordAlarmData) {
        return emsRecordAlarmDataMapper.selectEmsRecordAlarmDataList(emsRecordAlarmData);
    }

    /**
     * 新增异常数据记录
     *
     * @param emsRecordAlarmData 异常数据记录
     * @return 结果
     */
    @Override
    public int insertEmsRecordAlarmData(EmsRecordAlarmData emsRecordAlarmData) {
        emsRecordAlarmData.setCreateTime(DateUtils.getNowDate());
        return emsRecordAlarmDataMapper.insertEmsRecordAlarmData(emsRecordAlarmData);
    }

    /**
     * 修改异常数据记录
     *
     * @param emsRecordAlarmData 异常数据记录
     * @return 结果
     */
    @Override
    public int updateEmsRecordAlarmData(EmsRecordAlarmData emsRecordAlarmData) {
        emsRecordAlarmData.setUpdateTime(DateUtils.getNowDate());
        return emsRecordAlarmDataMapper.updateEmsRecordAlarmData(emsRecordAlarmData);
    }

    /**
     * 批量删除异常数据记录
     *
     * @param objIds 需要删除的异常数据记录主键
     * @return 结果
     */
    @Override
    public int deleteEmsRecordAlarmDataByObjIds(Long[] objIds) {
        return emsRecordAlarmDataMapper.deleteEmsRecordAlarmDataByObjIds(objIds);
    }

    /**
     * 删除异常数据记录信息
     *
     * @param objId 异常数据记录主键
     * @return 结果
     */
    @Override
    public int deleteEmsRecordAlarmDataByObjId(Long objId) {
        return emsRecordAlarmDataMapper.deleteEmsRecordAlarmDataByObjId(objId);
    }

    /**
     * 处理异常数据
     *
     * @param objIds
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int handleExceptionsAlarmData(Long[] objIds) {
        int result = 0;
        for (Long objId : objIds) {
            EmsRecordAlarmData alarmData = new EmsRecordAlarmData();
            alarmData.setObjId(objId);
            alarmData.setAlarmStatus(0L);
            alarmData.setOperationName(getUsername());
            alarmData.setOperationTime(DateUtils.getNowDate());
            int i = emsRecordAlarmDataMapper.updateEmsRecordAlarmData(alarmData);
            result += 1;
        }
        return result;
    }

    /**
     * 物联网数据阈值检查定时任务
     * 每分钟执行一次，检查当天分表中的最新数据是否超过阈值
     * 
     * 重构说明：
     * 1. 改为基于monitor_field字段的精确匹配，而非按设备类型检查所有字段
     * 2. 支持多字段设备的独立阈值规则（如振动设备的4个字段可设置不同阈值）
     * 3. 优化异常记录的cause字段，使用字典描述而非数据库字段名
     * 4. 修复数据关联：monitor_id存储的是monitor_code值，与采集数据分表保持一致
     * 5. 完全重构去重逻辑：确保绝对不会产生重复数据
     * 6. 支持大于阈值和小于阈值双重检查（trigger_rule: 0=大于阈值, 1=小于阈值）
     * 
     * 注意：此方法已停用，现在完全依赖WebSocket进行实时数据推送和告警处理
     */
//    @Scheduled(cron = "0 */1 * * * ?") // 已停用：完全依赖WebSocket，不再使用定时任务
//    @Override
//    public void checkIotenvThresholdAlarms() {
//        System.out.println("==== 开始执行阈值检查定时任务 ====");
//        long startTime = System.currentTimeMillis();
//        try {
//            // 1. 获取当天的分表名
//            SimpleDateFormat tableFormat = new SimpleDateFormat("yyyyMMdd");
//            String tableName = "record_iotenv_instant_" + tableFormat.format(new Date());
//
//            // 检查表是否存在
//            if (!checkTableExists(tableName)) {
//                System.out.println("当天分表不存在: " + tableName);
//                return;
//            }
//
//            // 2. 查询所有启用的告警规则（包括大于阈值和小于阈值）
//            List<EmsRecordAlarmRule> alarmRules = emsRecordAlarmRuleMapper.selectEmsRecordAlarmRuleList(new EmsRecordAlarmRule());
//
//            // 按触发规则分类
//            List<EmsRecordAlarmRule> greaterThanRules = new ArrayList<>();
//            List<EmsRecordAlarmRule> lessThanRules = new ArrayList<>();
//
//            for (EmsRecordAlarmRule rule : alarmRules) {
//                if (rule.getTriggerRule() != null) {
//                    if (rule.getTriggerRule() == 0L) {
//                        greaterThanRules.add(rule); // 大于阈值
//                    } else if (rule.getTriggerRule() == 1L) {
//                        lessThanRules.add(rule); // 小于阈值
//                    }
//                }
//            }
//
//            System.out.println("查询到的告警规则 - 大于阈值规则: " + greaterThanRules.size() +
//                             " 条, 小于阈值规则: " + lessThanRules.size() + " 条");
//
//            if (greaterThanRules.isEmpty() && lessThanRules.isEmpty()) {
//                System.out.println("没有启用的阈值告警规则");
//                return;
//            }
//
//            // 3. 按设备编码分组告警规则，每个设备可能有多个字段的规则
//            // 注意：monitor_id字段存储的实际是monitor_code值，与采集数据分表的monitorId保持一致
//            Map<String, List<EmsRecordAlarmRule>> rulesByMonitor = alarmRules.stream()
//                    .filter(rule -> ObjectUtil.isNotEmpty(rule.getMonitorId()))
//                    .collect(Collectors.groupingBy(EmsRecordAlarmRule::getMonitorId));
//
//            // 4. 只查询最近2分钟的数据，确保每分钟执行时不重复处理
//            Date twoMinutesAgo = new Date(System.currentTimeMillis() - 2 * 60 * 1000);
//            List<RecordIotenvInstant> recentRecords = recordIotenvInstantMapper.selectRecentRecordsFromTable(tableName, twoMinutesAgo);
//
//            System.out.println("从分表 " + tableName + " 查询到最近2分钟的数据条数: " + recentRecords.size());
//            if (!recentRecords.isEmpty()) {
//                System.out.println("数据时间范围: " + recentRecords.get(recentRecords.size()-1).getRecodeTime() +
//                                 " 到 " + recentRecords.get(0).getRecodeTime());
//            }
//
//            if (recentRecords.isEmpty()) {
//                System.out.println("当天分表最近2分钟无新数据: " + tableName);
//                return;
//            }
//
//            // 5. 获取所有相关设备信息（用于验证设备类型，确保规则合理性）
//            // 这里需要按monitor_code查询，因为rulesByMonitor的key是monitor_code
//            Set<String> monitorCodes = rulesByMonitor.keySet();
//            List<EmsBaseMonitorInfo> monitorInfruoyi = emsBaseMonitorInfoMapper.selectMonitorInfoByCodes(new ArrayList<>(monitorCodes));
//            Map<String, EmsBaseMonitorInfo> monitorInfoMap = monitorInfruoyi.stream()
//                    .collect(Collectors.toMap(EmsBaseMonitorInfo::getMonitorCode, m -> m));
//
//            // 6. 处理每条记录，基于精确的字段规则进行阈值检查
//            List<EmsRecordAlarmData> candidateAlarms = new ArrayList<>();
//            for (RecordIotenvInstant record : recentRecords) {
//                String monitorId = record.getMonitorId(); // 采集数据中的monitorId实际是monitor_code
//                List<EmsRecordAlarmRule> rules = rulesByMonitor.get(monitorId);
//
//                if (rules == null || rules.isEmpty()) {
//                    // 输出更详细的调试信息
//                    if (rulesByMonitor.containsKey(monitorId)) {
//                        System.out.println("设备 " + monitorId + " 的规则列表为空");
//                    } else {
//                        System.out.println("设备 " + monitorId + " 未找到对应的告警规则");
//                    }
//                    continue;
//                }
//
//                System.out.println("处理设备 " + monitorId + " 的数据，找到 " + rules.size() + " 条规则");
//
//                EmsBaseMonitorInfo monitorInfo = monitorInfoMap.get(monitorId);
//                if (monitorInfo == null) {
//                    System.out.println("警告：设备 " + monitorId + " 未找到设备信息");
//                    continue;
//                }
//
//                // 7. 遍历该设备的所有规则，支持新版本（有monitor_field）和历史版本（monitor_field为NULL）
//                for (EmsRecordAlarmRule rule : rules) {
//                    // 检查规则的基本有效性 - 只要有阈值就可以处理
//                    if (rule.getTriggerValue() == null) {
//                        System.out.println("跳过无阈值的规则 - 设备:" + monitorId + ", 规则ID:" + rule.getObjId());
//                        continue;
//                    }
//
//                    BigDecimal threshold = rule.getTriggerValue();
//                    List<BigDecimal> valuesToCheck = new ArrayList<>();
//                    List<String> fieldDescriptions = new ArrayList<>();
//
//                    // 8. 根据monitor_field字段处理不同情况
//                    if (rule.getMonitorField() != null) {
//                        // 新版本：有明确的monitor_field，精确检查指定字段
//
//                        // 验证监测字段是否符合设备类型（可选的业务校验）
//                        if (!isValidMonitorFieldForDeviceType(rule.getMonitorField(), monitorInfo.getMonitorType())) {
//                            System.out.println("警告：设备类型与监测字段不匹配 - 设备:" + monitorId +
//                                             ", 设备类型:" + monitorInfo.getMonitorType() +
//                                             ", 监测字段:" + rule.getMonitorField());
//                            continue;
//                        }
//
//                        BigDecimal actualValue = getFieldValue(record, rule.getMonitorField());
//                        if (actualValue != null) {
//                            valuesToCheck.add(actualValue);
//                            String fieldDesc = MONITOR_FIELD_TO_DESC.get(rule.getMonitorField());
//                            fieldDescriptions.add(fieldDesc != null ? fieldDesc : "未知字段");
//                        }
//
//                    } else {
//                        // 历史版本：monitor_field为NULL，根据设备类型检查相应的默认字段
//                        List<BigDecimal> defaultValues = getDefaultFieldValues(record, monitorInfo.getMonitorType());
//                        List<String> defaultDescriptions = getDefaultFieldDescriptions(monitorInfo.getMonitorType());
//
//                        if (!defaultValues.isEmpty()) {
//                            valuesToCheck.addAll(defaultValues);
//                            fieldDescriptions.addAll(defaultDescriptions);
//                            System.out.println("历史规则兼容处理 - 设备:" + monitorId +
//                                             ", 设备类型:" + monitorInfo.getMonitorType() +
//                                             ", 检查字段数:" + defaultValues.size());
//                        } else {
//                            System.out.println("警告：无法确定历史规则的检查字段 - 设备:" + monitorId +
//                                             ", 设备类型:" + monitorInfo.getMonitorType());
//                            continue;
//                        }
//                    }
//
//                    // 9. 阈值比较：根据触发规则检查所有相关字段
//                    for (int i = 0; i < valuesToCheck.size(); i++) {
//                        BigDecimal actualValue = valuesToCheck.get(i);
//                        String fieldDesc = fieldDescriptions.get(i);
//
//                        if (actualValue != null) {
//                            boolean isAlarmTriggered = false;
//                            String alarmDescription = "";
//
//                            // 根据触发规则判断是否触发告警
//                            if (rule.getTriggerRule() == 0L) {
//                                // 大于阈值检查
//                                if (actualValue.compareTo(threshold) > 0) {
//                                    isAlarmTriggered = true;
//                                    alarmDescription = "大于阈值";
//                                }
//                            } else if (rule.getTriggerRule() == 1L) {
//                                // 小于阈值检查
//                                if (actualValue.compareTo(threshold) < 0) {
//                                    isAlarmTriggered = true;
//                                    alarmDescription = "小于阈值";
//                                }
//                            }
//
//                            if (isAlarmTriggered) {
//                                EmsRecordAlarmData alarmData = createAlarmData(record, rule, actualValue.toString(), fieldDesc);
//                                candidateAlarms.add(alarmData);
//
//                                System.out.println("检测到阈值异常 - 设备:" + monitorId +
//                                                 ", 字段:" + fieldDesc +
//                                                 ", 实际值:" + actualValue +
//                                                 ", 阈值:" + threshold +
//                                                 ", 异常类型:" + alarmDescription +
//                                                 ", 设备采集时间:" + record.getCollectTime() +
//                                                 ", 系统记录时间:" + record.getRecodeTime());
//                            }
//                        }
//                    }
//                }
//            }
//
//            // 10. 使用严格的去重逻辑插入异常数据
//            if (!candidateAlarms.isEmpty()) {
//                int insertedCount = insertAlarmDataWithStrictDuplicateCheck(candidateAlarms);
//                System.out.println("严格去重后实际插入异常数据: " + insertedCount + " 条");
//            } else {
//                System.out.println("未检测到异常数据");
//            }
//
//        } catch (Exception e) {
//            System.err.println("阈值检查定时任务执行异常: " + e.getMessage());
//            e.printStackTrace();
//        } finally {
//            long executionTime = System.currentTimeMillis() - startTime;
//            System.out.println("==== 阈值检查定时任务执行完成，耗时: " + executionTime + "ms ====");
//        }
//    }

    /**
     * 根据监测字段获取记录中对应的数据值
     * 这是关键的字段映射方法，将字典值映射到具体的数据库字段
     * 
     * @param record 物联网数据记录
     * @param monitorField 监测字段字典值（0温度，1湿度，2振动-速度等）
     * @return 对应字段的数据值，如果字段不存在返回null
     */
    private BigDecimal getFieldValue(RecordIotenvInstant record, Long monitorField) {
        switch (monitorField.intValue()) {
            case 0: // 温度
                return record.getTemperature();
            case 1: // 湿度
                return record.getHumidity();
            case 2: // 振动-速度(mm/s)
                return record.getVibrationSpeed();
            case 3: // 振动-位移(um)
                return record.getVibrationDisplacement();
            case 4: // 振动-加速度(g)
                return record.getVibrationAcceleration();
            case 5: // 振动-温度(℃)
                return record.getVibrationTemp();
            case 6: // 噪音
                return record.getNoise();
            case 7: // 照度
                return record.getIlluminance();
            case 8: // 气体浓度
                return record.getConcentration();
            default:
                System.out.println("未知的监测字段: " + monitorField);
                return null;
        }
    }

    /**
     * 根据设备类型获取默认的检查字段值（用于历史规则兼容）
     * 
     * @param record 物联网数据记录
     * @param monitorType 设备类型
     * @return 需要检查的字段值列表
     */
    private List<BigDecimal> getDefaultFieldValues(RecordIotenvInstant record, Long monitorType) {
        List<BigDecimal> values = new ArrayList<>();
        
        if (monitorType == null) {
            return values;
        }
        
        switch (monitorType.intValue()) {
            case 5: // 纯温度设备
                if (record.getTemperature() != null) {
                    values.add(record.getTemperature());
                }
                break;
            case 6: // 温湿度设备
                if (record.getTemperature() != null) {
                    values.add(record.getTemperature());
                }
                if (record.getHumidity() != null) {
                    values.add(record.getHumidity());
                }
                break;
            case 10: // 振动设备
                if (record.getVibrationSpeed() != null) {
                    values.add(record.getVibrationSpeed());
                }
                if (record.getVibrationDisplacement() != null) {
                    values.add(record.getVibrationDisplacement());
                }
                if (record.getVibrationAcceleration() != null) {
                    values.add(record.getVibrationAcceleration());
                }
                if (record.getVibrationTemp() != null) {
                    values.add(record.getVibrationTemp());
                }
                break;
            default:
                // 其他设备类型，尝试检查所有非空字段
                if (record.getTemperature() != null) {
                    values.add(record.getTemperature());
                }
                if (record.getHumidity() != null) {
                    values.add(record.getHumidity());
                }
                if (record.getIlluminance() != null) {
                    values.add(record.getIlluminance());
                }
                if (record.getNoise() != null) {
                    values.add(record.getNoise());
                }
                if (record.getConcentration() != null) {
                    values.add(record.getConcentration());
                }
                break;
        }
        
        return values;
    }

    /**
     * 根据设备类型获取默认的字段描述（用于历史规则兼容）
     * 
     * @param monitorType 设备类型
     * @return 字段描述列表
     */
    private List<String> getDefaultFieldDescriptions(Long monitorType) {
        List<String> descriptions = new ArrayList<>();
        
        if (monitorType == null) {
            return descriptions;
        }
        
        switch (monitorType.intValue()) {
            case 5: // 纯温度设备
                descriptions.add("温度");
                break;
            case 6: // 温湿度设备
                descriptions.add("温度");
                descriptions.add("湿度");
                break;
            case 10: // 振动设备
                descriptions.add("振动-速度(mm/s)");
                descriptions.add("振动-位移(um)");
                descriptions.add("振动-加速度(g)");
                descriptions.add("振动-温度(℃)");
                break;
            default:
                // 其他设备类型的通用字段
                descriptions.add("温度");
                descriptions.add("湿度");
                descriptions.add("照度");
                descriptions.add("噪音");
                descriptions.add("气体浓度");
                break;
        }
        
        return descriptions;
    }

    /**
     * 验证监测字段是否符合设备类型
     * 业务规则校验，确保规则配置的合理性
     * 
     * @param monitorField 监测字段
     * @param monitorType 设备类型
     * @return 是否匹配
     */
    private boolean isValidMonitorFieldForDeviceType(Long monitorField, Long monitorType) {
        if (monitorField == null || monitorType == null) {
            return false;
        }
        
        // 温湿度设备(6)应该只能选择温度(0)或湿度(1)
        if (monitorType == 6L) {
            return monitorField == 0L || monitorField == 1L;
        }
        
        // 振动设备(10)应该只能选择振动相关字段(2,3,4,5)
        if (monitorType == 10L) {
            return monitorField >= 2L && monitorField <= 5L;
        }
        
        // 纯温度设备(5)只能选择温度(0)
        if (monitorType == 5L) {
            return monitorField == 0L;
        }
        
        // 其他设备类型支持噪音(6)、照度(7)、气体浓度(8)字段
        if (monitorField >= 6L && monitorField <= 8L) {
            return true;
        }
        
        // 默认支持温度和湿度字段
        return monitorField == 0L || monitorField == 1L;
    }

    /**
     * 创建异常数据对象
     * 使用字典描述作为cause，提高可读性
     * 
     * 重要修改：collectTime字段存储物联网数据的recordTime而非collectTime
     * 原因：设备的collectTime可能不准确，recordTime是系统记录时间，更可靠
     * 
     * @param record 物联网数据记录
     * @param rule 告警规则
     * @param actualValue 实际数值
     * @return 异常数据对象
     */
    private EmsRecordAlarmData createAlarmData(RecordIotenvInstant record, EmsRecordAlarmRule rule, String actualValue) {
        EmsRecordAlarmData alarmData = new EmsRecordAlarmData();
        alarmData.setMonitorId(record.getMonitorId());
        // 关键修改：存储recordTime而非collectTime，确保时间准确性
        alarmData.setCollectTime(record.getRecodeTime()); // 存储系统记录时间
        
        // 根据触发规则设置告警类型：0=大于阈值，1=小于阈值
        if (rule.getTriggerRule() != null && rule.getTriggerRule() == 1L) {
            alarmData.setAlarmType(1L); // 小于阈值
        } else {
            alarmData.setAlarmType(0L); // 大于阈值（默认）
        }
        
        alarmData.setAlarmStatus(1L); // 1表示未处理
        alarmData.setAlarmData(actualValue); // 记录实际超标数值
        
        // 使用字典描述作为异常原因，更加友好
        String fieldDesc = MONITOR_FIELD_TO_DESC.get(rule.getMonitorField());
        alarmData.setCause(fieldDesc != null ? fieldDesc : "未知字段");
        
        alarmData.setCreateTime(new Date());
        return alarmData;
    }

    /**
     * 创建异常数据对象（带自定义字段描述）
     * 用于历史规则兼容，支持自定义字段描述
     * 
     * @param record 物联网数据记录
     * @param rule 告警规则
     * @param actualValue 实际数值
     * @param fieldDescription 字段描述
     * @return 异常数据对象
     */
    private EmsRecordAlarmData createAlarmData(RecordIotenvInstant record, EmsRecordAlarmRule rule, String actualValue, String fieldDescription) {
        EmsRecordAlarmData alarmData = new EmsRecordAlarmData();
        alarmData.setMonitorId(record.getMonitorId());
        // 关键修改：存储recordTime而非collectTime，确保时间准确性
        alarmData.setCollectTime(record.getRecodeTime()); // 存储系统记录时间
        
        // 根据触发规则设置告警类型：0=大于阈值，1=小于阈值
        if (rule.getTriggerRule() != null && rule.getTriggerRule() == 1L) {
            alarmData.setAlarmType(1L); // 小于阈值
        } else {
            alarmData.setAlarmType(0L); // 大于阈值（默认）
        }
        
        alarmData.setAlarmStatus(1L); // 1表示未处理
        alarmData.setAlarmData(actualValue); // 记录实际超标数值
        
        // 使用传入的字段描述
        alarmData.setCause(ObjectUtil.isNotEmpty(fieldDescription) ? fieldDescription : "未知字段");
        
        alarmData.setCreateTime(new Date());
        return alarmData;
    }
    
    /**
     * 使用严格的两层去重逻辑插入异常数据
     * 
     * 重构说明：
     * 1. 第一层：批次内去重 - 对同一批候选数据进行去重，避免同批次内的重复
     * 2. 第二层：数据库去重 - 与数据库已有记录进行重复检查
     * 3. 时间基准修正：基于recordTime（存储在collectTime字段中）进行时间窗口计算
     * 4. 防重复策略：同一设备的同一字段在10分钟内只记录一次异常
     * 
     * @param alarmDataList 待插入的异常数据列表
     * @return 实际插入的异常数据数量
     */
    private int insertAlarmDataWithStrictDuplicateCheck(List<EmsRecordAlarmData> alarmDataList) {
        if (alarmDataList == null || alarmDataList.isEmpty()) {
            return 0;
        }
        
        // 第一层：批次内去重
        List<EmsRecordAlarmData> deduplicatedList = performBatchDeduplication(alarmDataList);
        System.out.println("批次内去重：原始 " + alarmDataList.size() + " 条，去重后 " + deduplicatedList.size() + " 条");
        
        // 第二层：数据库去重并插入
        int insertedCount = 0;
        long fiveMinutesInMs = 5 * 60 * 1000; // 10分钟去重窗口（前后各5分钟），避免短时间内重复告警
        
        for (EmsRecordAlarmData alarmData : deduplicatedList) {
            try {
                // 获取记录时间（现在存储的是recordTime）
                Date recordTime = alarmData.getCollectTime();
                if (recordTime == null) {
                    System.out.println("跳过无记录时间的异常数据");
                    continue;
                }
                
                // 构建10分钟的时间窗口（基于recordTime）
                Date startTime = new Date(recordTime.getTime() - fiveMinutesInMs);
                Date endTime = new Date(recordTime.getTime() + fiveMinutesInMs);
                
                // 查询数据库是否已存在相同的异常记录
                Integer existingCount = emsRecordAlarmDataMapper.checkDuplicateAlarmData(
                    alarmData.getMonitorId(),
                    alarmData.getCause(),
                    startTime,
                    endTime
                );
                
                // 如果不存在重复记录，则插入
                if (existingCount == null || existingCount == 0) {
                    int result = insertEmsRecordAlarmData(alarmData);
                    if (result > 0) {
                        insertedCount++;
                        System.out.println("成功插入异常数据 - 设备:" + alarmData.getMonitorId() + 
                                         ", 原因:" + alarmData.getCause() + 
                                         ", 记录时间:" + alarmData.getCollectTime() +
                                         ", 数值:" + alarmData.getAlarmData());
                    }
                } else {
                    System.out.println("跳过重复异常数据 - 设备:" + alarmData.getMonitorId() + 
                                     ", 原因:" + alarmData.getCause() + 
                                     ", 记录时间:" + alarmData.getCollectTime() + 
                                     ", 10分钟内已存在 " + existingCount + " 条相同记录");
                }
                
            } catch (Exception e) {
                System.err.println("插入异常数据时发生错误: " + e.getMessage());
                e.printStackTrace();
            }
        }
        
        return insertedCount;
    }
    
    /**
     * 执行批次内去重
     * 去重规则：相同设备 + 相同字段类型 + 相同记录时间（精确到秒）的记录视为重复
     * 保留第一条记录，丢弃后续重复记录
     * 
     * @param alarmDataList 原始异常数据列表
     * @return 去重后的异常数据列表
     */
    private List<EmsRecordAlarmData> performBatchDeduplication(List<EmsRecordAlarmData> alarmDataList) {
        if (alarmDataList == null || alarmDataList.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 使用LinkedHashMap保持插入顺序，同时去重
        Map<String, EmsRecordAlarmData> uniqueRecords = new LinkedHashMap<>();
        
        for (EmsRecordAlarmData alarmData : alarmDataList) {
            // 构建唯一标识：设备ID + 字段类型 + 记录时间（精确到秒）
            String uniqueKey = buildUniqueKey(alarmData);
            
            if (uniqueKey != null && !uniqueRecords.containsKey(uniqueKey)) {
                uniqueRecords.put(uniqueKey, alarmData);
            } else if (uniqueKey != null) {
                System.out.println("批次内发现重复记录，已跳过 - " + uniqueKey);
            }
        }
        
        return new ArrayList<>(uniqueRecords.values());
    }
    
    /**
     * 构建异常数据的唯一标识
     * 格式：设备ID_字段类型_记录时间戳(秒)
     * 
     * @param alarmData 异常数据
     * @return 唯一标识字符串，如果数据不完整返回null
     */
    private String buildUniqueKey(EmsRecordAlarmData alarmData) {
        if (alarmData == null || 
            ObjectUtil.isEmpty(alarmData.getMonitorId()) || 
            ObjectUtil.isEmpty(alarmData.getCause()) || 
            alarmData.getCollectTime() == null) {
            return null;
        }
        
        // 将时间精确到秒，避免毫秒级的微小差异
        long timeInSeconds = alarmData.getCollectTime().getTime() / 1000;
        
        return alarmData.getMonitorId() + "_" + 
               alarmData.getCause() + "_" + 
               timeInSeconds;
    }
    
    /**
     * 检查数据库表是否存在
     * 
     * @param tableName 表名
     * @return 是否存在
     */
    private boolean checkTableExists(String tableName) {
        Map<String, Object> params = new HashMap<>();
        params.put("tableName", tableName);
        Integer count = recordIotenvInstantMapper.checkTableExists(params);
        return count != null && count > 0;
    }

    /**
     * 获取异常数据表总数（包含所有告警类型）
     */
    @Override
    public int getAlarmDataTotalCount() {
        return emsRecordAlarmDataMapper.getAlarmDataTotalCount();
    }
    
    /**
     * 批量保存WebSocket告警数据
     * 处理前端传来的告警数据列表，直接插入数据库
     * 
     * @param alarmDataList 告警数据列表
     * @return 实际插入的记录数量
     */
    @Override
    public int saveWebSocketAlarmDataBatch(List<EmsRecordAlarmData> alarmDataList) {
        if (alarmDataList == null || alarmDataList.isEmpty()) {
            return 0;
        }
        
        System.out.println("==== 开始保存WebSocket告警数据 ====");
        System.out.println("接收到告警数据数量: " + alarmDataList.size());
        
        // 设置默认值和创建时间
        Date currentTime = DateUtils.getNowDate();
        int insertedCount = 0;
        
        for (EmsRecordAlarmData alarmData : alarmDataList) {
            try {
                // 设置创建时间
                if (alarmData.getCreateTime() == null) {
                    alarmData.setCreateTime(currentTime);
                }
                
                // 设置默认告警状态为未处理
                if (alarmData.getAlarmStatus() == null) {
                    alarmData.setAlarmStatus(1L); // 1表示未处理
                }
                
                // 数据完整性检查
                if (ObjectUtil.isEmpty(alarmData.getMonitorId())) {
                    System.out.println("警告：跳过monitorId为空的告警数据");
                    continue;
                }
                
                if (alarmData.getCollectTime() == null) {
                    System.out.println("警告：collectTime为空，使用当前时间");
                    alarmData.setCollectTime(currentTime);
                }
                
                System.out.println("保存告警数据 - 设备:" + alarmData.getMonitorId() + 
                                 ", 原因:" + alarmData.getCause() + 
                                 ", 数值:" + alarmData.getAlarmData() + 
                                 ", 告警类型:" + alarmData.getAlarmType());
                
                // 直接插入数据库，不进行去重检查
                int result = insertEmsRecordAlarmData(alarmData);
                if (result > 0) {
                    insertedCount++;
                    System.out.println("成功保存告警数据 - 设备:" + alarmData.getMonitorId() + 
                                     ", 原因:" + alarmData.getCause());
                }
                
            } catch (Exception e) {
                System.err.println("保存告警数据时发生错误: " + e.getMessage());
                e.printStackTrace();
            }
        }
        
        System.out.println("WebSocket告警数据保存完成，实际插入: " + insertedCount + " 条记录");
        System.out.println("==== WebSocket告警数据保存结束 ====");
        
        return insertedCount;
    }
}
