package com.dcs.hnyz.service.impl;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dcs.common.enums.GeneralStatus;
import com.dcs.hnyz.cache.CacheCenter;
import com.dcs.hnyz.domain.AlarmEvent;
import com.dcs.hnyz.domain.vo.EquipmentParamFormVO;
import com.dcs.hnyz.enums.OperationType;
import com.dcs.hnyz.service.IAlarmEventService;
import com.dcs.hnyz.service.IEquipmentParamService;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import com.dcs.hnyz.mapper.AlarmConfigMapper;
import com.dcs.hnyz.domain.AlarmConfig;
import com.dcs.hnyz.service.IAlarmConfigService;

import javax.annotation.Resource;

import static com.dcs.framework.datasource.DynamicDataSourceContextHolder.log;

/**
 * 告警配置管理Service业务层处理
 *
 * @author hmy
 * @date 2025-05-22
 */
@Service
public class AlarmConfigServiceImpl implements IAlarmConfigService {
    @Resource
    private AlarmConfigMapper alarmConfigMapper;

    @Resource
    private IEquipmentParamService equipmentParamService;

    @Resource
    private IAlarmEventService alarmEventService;

    // 缓存结构：寄存器唯一code ->  List<AlarmConfig>>
    private final Map<String, List<AlarmConfig>> codeConfigMap = new ConcurrentHashMap<>();


    // key: 寄存器唯一code + alarmCode, AlarmEvent 对象 告警事件（用于延迟判断和状态追踪）
    private final Map<String, AlarmEvent> alarmEventMap = new ConcurrentHashMap<>();

    private static final String STATUS_UNRECOVERED = "0";//未恢复
    private static final String STATUS_RECOVERED = "1";//已恢复

    /**
     * 查询告警配置管理
     *
     * @param configId 告警配置管理主键
     * @return 告警配置管理
     */
    @Override
    public AlarmConfig selectAlarmConfigByConfigId(Long configId) {
        return alarmConfigMapper.selectAlarmConfigByConfigId(configId);
    }

    /**
     * 查询告警配置管理列表
     *
     * @param alarmConfig 告警配置管理
     * @return 告警配置管理
     */
    @Override
    public List<AlarmConfig> selectAlarmConfigList(AlarmConfig alarmConfig) {
        return alarmConfigMapper.selectAlarmConfigList(alarmConfig);
    }

    /**
     * 新增告警配置管理
     *
     * @param alarmConfig 告警配置管理
     * @return 结果
     */
    @Override
    public int insertAlarmConfig(AlarmConfig alarmConfig) {
        return alarmConfigMapper.insert(alarmConfig);
    }

    /**
     * 修改告警配置管理
     *
     * @param alarmConfig 告警配置管理
     * @return 结果
     */
    @Override
    public int updateAlarmConfig(AlarmConfig alarmConfig) {
        return alarmConfigMapper.updateById(alarmConfig);
    }

    /**
     * 批量删除告警配置管理
     *
     * @param configIds 需要删除的告警配置管理主键
     * @return 结果
     */
    @Override
    public int deleteAlarmConfigByConfigIds(Long[] configIds) {
        return alarmConfigMapper.deleteBatchIds(Arrays.asList(configIds));
    }

    /**
     * 删除告警配置管理信息
     *
     * @param configId 告警配置管理主键
     * @return 结果
     */
    @Override
    public int deleteAlarmConfigByConfigId(Long configId) {
        return alarmConfigMapper.deleteById(configId);
    }

    @EventListener(ApplicationReadyEvent.class)
    public void init() {
        if (equipmentParamService == null) {
            log.error("equipmentParamService is null!");
            return;
        }
        reload();
    }

    @Override
    public void reload() {
        codeConfigMap.clear();
        LambdaQueryWrapper<AlarmConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AlarmConfig::getStatus, GeneralStatus.ENABLE.getCode());
        List<AlarmConfig> allConfigs = alarmConfigMapper.selectList(queryWrapper);
        for (AlarmConfig config : allConfigs) {
            String code = equipmentParamService.getCodeByParentId(config.getEquipmentId());
            if (code == null) continue;
            codeConfigMap.computeIfAbsent(code, k -> new ArrayList<>()).add(config);
        }
        log.info("[告警配置] 缓存加载完成，共 {} 条", codeConfigMap.size());//配置的设备数量
    }

    /**
     * 根据code从内存缓存中获取 对应的告警配置列表
     *
     * @param code
     * @return
     */
    public List<AlarmConfig> getConfigsByCode(String code) {
        return codeConfigMap.getOrDefault(code, Collections.emptyList());
    }

    /**
     * 判断单条告警是否触发
     *
     * @param code   寄存器唯一code
     * @param config 告警配置
     * @param value  寄存器实时数据
     * @param param  寄存器相关参数
     * @return
     */
    private AlarmEvent checkAlarmWithDelay(String code, AlarmConfig config, String value, EquipmentParamFormVO param) {
        String key = code + "_" + config.getAlarmCode();
        long now = System.currentTimeMillis();
        Date nowDate = new Date(now);

        String threshold = config.getThresholdValue();//阈值
        long delayMillis = (config.getDelaySeconds() != null ? config.getDelaySeconds() : 0) * 1000L;

        boolean overThreshold;//是否超过阈值
        try {
            OperationType op = config.getThresholdType(); // 已由 MyBatis 自动转为枚举
            overThreshold = op.apply(value, threshold);
        } catch (Exception e) {
            return null; // 操作符异常或阈值解析失败
        }

        AlarmEvent cached = alarmEventMap.get(key);

        // ========== 情况 1：超过阈值 ==========
        if (overThreshold) {
            // 首次触发，创建缓存
            if (cached == null) {
                AlarmEvent event = AlarmEvent.from(param, config);
                event.setOccurTime(nowDate);
                alarmEventMap.put(key, event);
                return null;
            }

            // 缓存存在但未插入数据库
            long firstTime = cached.getOccurTime().getTime();
            if (now - firstTime >= delayMillis) {
                if(cached.getStatus() == STATUS_UNRECOVERED) {
                    return null; // 状态未恢复，不重复往数据库插数据
                }
                cached.setStatus(STATUS_UNRECOVERED);
                cached.setMessage("告警触发: " + config.getAlarmName());
                alarmEventService.insertAlarmEvent(cached);
                alarmEventMap.put(key, cached);//把id更新进缓存
                return cached;
            }
            return null; // 延迟未到，不触发
        }

        // ========== 情况 2：未超过阈值（考虑恢复） ==========
        if (cached != null) {//缓存中有该数据
            long firstTime = cached.getOccurTime().getTime();
            if (now - firstTime >= delayMillis) {
                cached.setRecoverTime(nowDate);
                cached.setStatus(STATUS_RECOVERED);
                cached.setMessage("告警恢复: " + config.getAlarmName());
                alarmEventService.updateAlarmEvent(cached);
                alarmEventMap.remove(key); // 已恢复则移除缓存
                return cached;
            }
            alarmEventMap.remove(key); // 已恢复则移除缓存
        }
        return null;
    }

    /**
     * 批量判断设备数据是否触发告警，返回触发告警事件列表
     */
    public List<AlarmEvent> checkAlarms() {
        List<AlarmEvent> triggeredAlarms = new ArrayList<>();
        for (Map.Entry<String, List<AlarmConfig>> entry : codeConfigMap.entrySet()) {
            String code = entry.getKey();
            EquipmentParamFormVO param = CacheCenter.registerNowDataMap.get(code);
            if (param == null) continue;

            String valueStr = param.getValue().toString();
            //获取当前告警配置 Map<String, List<AlarmConfig>> 中的一个 code 所对应的告警配置列表。 并将这个 List<AlarmConfig> 转为 Stream
            entry.getValue().stream()
                    //过滤出真正触发的告警事件、告警恢复事件,转换成一个 AlarmEvent 对象,前端弹窗提示
                    .map(config -> checkAlarmWithDelay(code, config, valueStr, param))
                    .filter(Objects::nonNull)
                    //把每个构建好的 AlarmEvent 添加到结果列表 triggeredAlarms
                    .forEach(triggeredAlarms::add);
        }
        return triggeredAlarms;
    }


}
