/*
 * 文 件 名:  AlarmProcessService
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  <描述>
 * 修 改 人:  lvwenbin
 * 修改时间:  2026/2/3
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.ruoyi.ems.service.alarm;

/**
 * <一句话功能简述>
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2026/2/3]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */

import com.ruoyi.ems.domain.Alarm;
import com.ruoyi.ems.domain.AlarmHandle;
import com.ruoyi.ems.domain.AlarmRule;
import com.ruoyi.ems.domain.EmsDevice;
import com.ruoyi.ems.mapper.AlarmMapper;
import com.ruoyi.ems.mapper.AlarmHandleMapper;
import com.ruoyi.ems.service.IAlarmRuleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 告警处理服务
 *
 * 【核心功能】
 * 1. 告警生成：根据规则引擎结果生成告警
 * 2. 告警聚合：同一规则同一对象的重复告警进行聚合
 * 3. 告警恢复：检测到恢复时自动更新状态
 * 4. 告警冷却：防止频繁告警
 * 5. 告警处置：确认、处置、关闭等操作
 */
@Slf4j
@Service
public class AlarmProcessService {

    @Autowired
    private AlarmRuleEngine ruleEngine;

    @Autowired
    private AlarmMapper alarmMapper;

    @Autowired
    private AlarmHandleMapper handleMapper;

    @Autowired
    private IAlarmRuleService ruleService;

    /** 告警冷却缓存 Map<ruleCode_targetCode, lastAlarmTime> */
    private final ConcurrentHashMap<String, Long> coolDownCache = new ConcurrentHashMap<>();

    /** 连续触发计数 Map<ruleCode_targetCode, count> */
    private final ConcurrentHashMap<String, Integer> triggerCountCache = new ConcurrentHashMap<>();

    /**
     * 处理设备属性变化（实时监测入口）
     *
     * @param device 设备信息
     * @param attrKey 变化的属性
     * @param attrValue 属性新值
     * @param oldValue 属性旧值(可选)
     * @return 生成的告警列表
     */
    @Transactional(rollbackFor = Exception.class)
    public List<Alarm> processAttrChange(EmsDevice device, String attrKey, String attrValue, String oldValue) {
        List<Alarm> alarms = new ArrayList<>();

        if (device == null || StringUtils.isBlank(attrKey)) {
            return alarms;
        }

        // 查询适用的实时监测规则
        List<AlarmRule> rules = ruleService.selectRulesForRealtime(device.getDeviceModel(), attrKey);
        if (CollectionUtils.isEmpty(rules)) {
            return alarms;
        }

        // 构建属性值Map
        Map<String, String> attrValues = new HashMap<>();
        attrValues.put(attrKey, attrValue);

        // 执行规则检查
        List<AlarmRuleEngine.CheckResult> results = ruleEngine.checkRules(rules, device, attrValues);

        for (AlarmRuleEngine.CheckResult result : results) {
            if (result.isTriggered()) {
                Alarm alarm = processTriggered(result, device, Alarm.SOURCE_REALTIME, null);
                if (alarm != null) {
                    alarms.add(alarm);
                }
            } else if (result.isRecovered()) {
                processRecovered(result, device);
            }
        }

        return alarms;
    }

    /**
     * 批量处理设备检查（巡检入口）
     *
     * @param device 设备信息
     * @param attrValues 属性值Map
     * @param sourceRef 来源引用（如巡检报告代码）
     * @return 生成的告警列表
     */
    @Transactional(rollbackFor = Exception.class)
    public List<Alarm> processInspection(EmsDevice device, Map<String, String> attrValues, String sourceRef) {
        List<Alarm> alarms = new ArrayList<>();

        if (device == null || attrValues == null || attrValues.isEmpty()) {
            return alarms;
        }

        // 查询适用的巡检规则
        List<AlarmRule> rules = ruleService.selectRulesForInspection(device.getDeviceModel());
        if (CollectionUtils.isEmpty(rules)) {
            return alarms;
        }

        // 执行规则检查
        List<AlarmRuleEngine.CheckResult> results = ruleEngine.checkRules(rules, device, attrValues);

        for (AlarmRuleEngine.CheckResult result : results) {
            if (result.isTriggered()) {
                Alarm alarm = processTriggered(result, device, Alarm.SOURCE_INSPECTION, sourceRef);
                if (alarm != null) {
                    alarms.add(alarm);
                }
            } else if (result.isRecovered()) {
                processRecovered(result, device);
            }
        }

        return alarms;
    }

    /**
     * 手动上报告警
     *
     * @param alarm 告警信息
     * @param reporter 上报人
     * @return 告警记录
     */
    @Transactional(rollbackFor = Exception.class)
    public Alarm reportAlarm(Alarm alarm, String reporter) {
        if (alarm == null) {
            throw new RuntimeException("告警信息不能为空");
        }

        // 设置基本信息
        alarm.setAlarmId(generateAlarmId());
        alarm.setAlarmSource(Alarm.SOURCE_MANUAL);
        alarm.setAlarmTime(new Date());
        alarm.setAlarmDate(new Date());
        alarm.setAlarmStatus(Alarm.STATUS_ACTIVE);
        alarm.setRepeatCount(1);
        alarm.setLastOccurTime(new Date());
        alarm.setIsNotified(0);
        alarm.setCreateBy(reporter);

        alarmMapper.insert(alarm);
        log.info("手动上报告警成功: alarmId={}, target={}", alarm.getAlarmId(), alarm.getTargetCode());

        return alarm;
    }

    /**
     * 确认告警
     *
     * @param alarmId 告警ID
     * @param operator 操作人
     * @param remark 备注
     */
    @Transactional(rollbackFor = Exception.class)
    public void confirmAlarm(String alarmId, String operator, String remark) {
        Alarm alarm = alarmMapper.selectByAlarmId(alarmId);
        if (alarm == null) {
            throw new RuntimeException("告警不存在: " + alarmId);
        }

        if (alarm.getAlarmStatus() != Alarm.STATUS_ACTIVE) {
            throw new RuntimeException("只能确认活动状态的告警");
        }

        // 更新状态
        alarm.setAlarmStatus(Alarm.STATUS_CONFIRMED);
        alarm.setConfirmTime(new Date());
        alarm.setConfirmBy(operator);
        alarm.setUpdateBy(operator);
        alarmMapper.update(alarm);

        // 记录处置
        addHandle(alarmId, AlarmHandle.TYPE_CONFIRM, remark, null, operator);

        log.info("告警已确认: alarmId={}, operator={}", alarmId, operator);
    }

    /**
     * 处置告警
     *
     * @param alarmId 告警ID
     * @param handleContent 处置内容
     * @param handleResult 处置结果
     * @param operator 操作人
     */
    @Transactional(rollbackFor = Exception.class)
    public void handleAlarm(String alarmId, String handleContent, String handleResult, String operator) {
        Alarm alarm = alarmMapper.selectByAlarmId(alarmId);
        if (alarm == null) {
            throw new RuntimeException("告警不存在: " + alarmId);
        }

        if (alarm.isEnded()) {
            throw new RuntimeException("告警已结束，无法处置");
        }

        // 更新状态
        alarm.setAlarmStatus(Alarm.STATUS_HANDLING);
        alarm.setUpdateBy(operator);
        alarmMapper.update(alarm);

        // 记录处置
        addHandle(alarmId, AlarmHandle.TYPE_HANDLE, handleContent, handleResult, operator);

        log.info("告警处置中: alarmId={}, operator={}", alarmId, operator);
    }

    /**
     * 解决告警
     *
     * @param alarmId 告警ID
     * @param resolveRemark 解决备注
     * @param operator 操作人
     */
    @Transactional(rollbackFor = Exception.class)
    public void resolveAlarm(String alarmId, String resolveRemark, String operator) {
        Alarm alarm = alarmMapper.selectByAlarmId(alarmId);
        if (alarm == null) {
            throw new RuntimeException("告警不存在: " + alarmId);
        }

        if (alarm.isEnded()) {
            throw new RuntimeException("告警已结束");
        }

        Date now = new Date();

        // 更新状态
        alarm.setAlarmStatus(Alarm.STATUS_RESOLVED);
        alarm.setResolveTime(now);
        alarm.setResolveBy(operator);
        alarm.setResolveRemark(resolveRemark);
        alarm.setDuration(alarm.calculateDuration());
        alarm.setUpdateBy(operator);
        alarmMapper.update(alarm);

        // 记录处置
        addHandle(alarmId, AlarmHandle.TYPE_CLOSE, resolveRemark, "已解决", operator);

        log.info("告警已解决: alarmId={}, operator={}, duration={}s", alarmId, operator, alarm.getDuration());
    }

    /**
     * 关闭告警（无需处置）
     *
     * @param alarmId 告警ID
     * @param reason 关闭原因
     * @param operator 操作人
     */
    @Transactional(rollbackFor = Exception.class)
    public void closeAlarm(String alarmId, String reason, String operator) {
        Alarm alarm = alarmMapper.selectByAlarmId(alarmId);
        if (alarm == null) {
            throw new RuntimeException("告警不存在: " + alarmId);
        }

        if (alarm.isEnded()) {
            throw new RuntimeException("告警已结束");
        }

        Date now = new Date();

        // 更新状态
        alarm.setAlarmStatus(Alarm.STATUS_CLOSED);
        alarm.setResolveTime(now);
        alarm.setResolveBy(operator);
        alarm.setResolveRemark(reason);
        alarm.setDuration(alarm.calculateDuration());
        alarm.setUpdateBy(operator);
        alarmMapper.update(alarm);

        // 记录处置
        addHandle(alarmId, AlarmHandle.TYPE_CLOSE, reason, "已关闭", operator);

        log.info("告警已关闭: alarmId={}, operator={}, reason={}", alarmId, operator, reason);
    }

    /**
     * 批量确认告警
     */
    @Transactional(rollbackFor = Exception.class)
    public int batchConfirm(List<String> alarmIds, String operator) {
        int count = 0;
        for (String alarmId : alarmIds) {
            try {
                confirmAlarm(alarmId, operator, "批量确认");
                count++;
            } catch (Exception e) {
                log.warn("批量确认告警失败: alarmId={}, error={}", alarmId, e.getMessage());
            }
        }
        return count;
    }

    // ==================== 私有方法 ====================

    /**
     * 处理触发的告警
     */
    private Alarm processTriggered(AlarmRuleEngine.CheckResult result, EmsDevice device, int source, String sourceRef) {
        AlarmRule rule = result.getRule();
        if (rule == null) {
            return null;
        }

        String cacheKey = rule.getRuleCode() + "_" + device.getDeviceCode();

        // 检查冷却时间
        if (!checkCoolDown(cacheKey, rule.getCoolDown())) {
            log.debug("告警处于冷却期，跳过: rule={}, device={}", rule.getRuleCode(), device.getDeviceCode());
            return null;
        }

        // 检查连续触发次数
        if (!checkTriggerCount(cacheKey, rule.getTriggerCount())) {
            log.debug("连续触发次数未达到阈值: rule={}, device={}", rule.getRuleCode(), device.getDeviceCode());
            return null;
        }

        // 查找是否存在活动告警（用于聚合）
        Alarm existingAlarm = alarmMapper.selectActiveAlarm(rule.getRuleCode(), device.getDeviceCode());

        if (existingAlarm != null) {
            // 聚合：更新重复次数和最后发生时间
            existingAlarm.setRepeatCount(existingAlarm.getRepeatCount() + 1);
            existingAlarm.setLastOccurTime(new Date());
            existingAlarm.setAttrValue(result.getAttrValue());
            alarmMapper.update(existingAlarm);

            log.debug("告警聚合: alarmId={}, repeatCount={}", existingAlarm.getAlarmId(), existingAlarm.getRepeatCount());
            return existingAlarm;
        }

        // 创建新告警
        Alarm alarm = ruleEngine.createAlarm(result, device, source, sourceRef);
        if (alarm != null) {
            alarmMapper.insert(alarm);

            // 更新冷却缓存
            coolDownCache.put(cacheKey, System.currentTimeMillis());
            // 重置触发计数
            triggerCountCache.remove(cacheKey);

            log.info("生成告警: alarmId={}, rule={}, device={}, value={}",
                alarm.getAlarmId(), rule.getRuleCode(), device.getDeviceCode(), result.getAttrValue());
        }

        return alarm;
    }

    /**
     * 处理恢复
     */
    private void processRecovered(AlarmRuleEngine.CheckResult result, EmsDevice device) {
        AlarmRule rule = result.getRule();
        if (rule == null) {
            return;
        }

        // 查找活动告警
        Alarm activeAlarm = alarmMapper.selectActiveAlarm(rule.getRuleCode(), device.getDeviceCode());
        if (activeAlarm == null) {
            return;
        }

        // 更新为已恢复
        Date now = new Date();
        activeAlarm.setAlarmStatus(Alarm.STATUS_RECOVERED);
        activeAlarm.setRecoveryTime(now);
        activeAlarm.setDuration(activeAlarm.calculateDuration());
        alarmMapper.update(activeAlarm);

        log.info("告警自动恢复: alarmId={}, rule={}, device={}",
            activeAlarm.getAlarmId(), rule.getRuleCode(), device.getDeviceCode());
    }

    /**
     * 检查冷却时间
     */
    private boolean checkCoolDown(String cacheKey, Integer coolDown) {
        if (coolDown == null || coolDown <= 0) {
            return true;
        }

        Long lastTime = coolDownCache.get(cacheKey);
        if (lastTime == null) {
            return true;
        }

        long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
        return elapsed >= coolDown;
    }

    /**
     * 检查连续触发次数
     */
    private boolean checkTriggerCount(String cacheKey, Integer requiredCount) {
        if (requiredCount == null || requiredCount <= 1) {
            return true;
        }

        Integer currentCount = triggerCountCache.compute(cacheKey, (k, v) -> v == null ? 1 : v + 1);
        return currentCount >= requiredCount;
    }

    /**
     * 添加处置记录
     */
    private void addHandle(String alarmId, int handleType, String content, String result, String operator) {
        AlarmHandle handle = new AlarmHandle();
        handle.setAlarmId(alarmId);
        handle.setHandleType(handleType);
        handle.setHandleContent(content);
        handle.setHandleResult(result);
        handle.setHandleBy(operator);
        handle.setHandleTime(new Date());
        handleMapper.insert(handle);
    }

    /**
     * 生成告警ID
     */
    private String generateAlarmId() {
        return "ALM" + System.currentTimeMillis() + String.format("%04d", new Random().nextInt(10000));
    }
}
