package com.ruoyi.ems.task;

import com.ruoyi.ems.domain.OpEnergyStrategyTrigger;
import com.ruoyi.ems.service.IOpEnergyStrategyTriggerService;
import com.ruoyi.ems.strategy.evaluator.ConditionEvaluator;
import com.ruoyi.ems.strategy.executor.StrategyExecutor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 策略触发监听器 (事件 / 属性）
 *
 * 针对 StrategyScheduler 的新版 registerTrigger() 逻辑进行了修复：
 * - registerEventTrigger()
 * - registerAttrTrigger()
 * - unregisterTriggers()
 * - clearAll()
 * - 分发入口 onEventReceived() / onAttrChanged()
 *
 * @author
 */
@Slf4j
@Component
public class StrategyTriggerListener {

    @Autowired
    private IOpEnergyStrategyTriggerService triggerService;

    @Autowired
    private ConditionEvaluator conditionEvaluator;

    @Autowired
    private ApplicationContext applicationContext;

    private StrategyExecutor strategyExecutor;

    /** key = objCode:eventKey  */
    private final Map<String, List<TriggerInfo>> eventTriggers = new ConcurrentHashMap<>();

    /** key = objCode:attrKey */
    private final Map<String, List<TriggerInfo>> attrTriggers = new ConcurrentHashMap<>();

    /** 缓存触发器 → 用于注销 */
    private final Map<String, List<TriggerInfo>> strategyTriggerIndex = new ConcurrentHashMap<>();


    // 延迟加载
    private StrategyExecutor getStrategyExecutor() {
        if (strategyExecutor == null) {
            synchronized (this) {
                if (strategyExecutor == null) {
                    strategyExecutor = applicationContext.getBean(StrategyExecutor.class);
                }
            }
        }
        return strategyExecutor;
    }

    /* ============================================================
     * 注册触发器
     * ============================================================ */

    /** 单个事件触发器 */
    public void registerEventTrigger(String strategyCode, OpEnergyStrategyTrigger trigger) {
        String key = trigger.getSourceObjCode() + ":" + trigger.getEventKey();

        TriggerInfo info = new TriggerInfo(strategyCode, trigger);

        eventTriggers.computeIfAbsent(key, k -> new ArrayList<>()).add(info);

        // 建立反向索引，注销时用
        strategyTriggerIndex.computeIfAbsent(strategyCode, k -> new ArrayList<>()).add(info);

        log.info("事件触发器已注册: key={}, strategy={}", key, strategyCode);
    }

    /** 单个属性触发器 */
    public void registerAttrTrigger(String strategyCode, OpEnergyStrategyTrigger trigger) {
        String key = trigger.getSourceObjCode() + ":" + trigger.getAttrKey();

        TriggerInfo info = new TriggerInfo(strategyCode, trigger);

        attrTriggers.computeIfAbsent(key, k -> new ArrayList<>()).add(info);
        strategyTriggerIndex.computeIfAbsent(strategyCode, k -> new ArrayList<>()).add(info);

        log.info("属性触发器已注册: key={}, strategy={}", key, strategyCode);
    }


    /* ============================================================
     * 注销 & 清空
     * ============================================================ */

    /** 注销某个策略的所有事件/属性触发器 */
    public void unregisterTriggers(String strategyCode) {
        List<TriggerInfo> list = strategyTriggerIndex.remove(strategyCode);
        if (list == null || list.isEmpty()) return;

        for (TriggerInfo info : list) {
            OpEnergyStrategyTrigger t = info.getTrigger();
            String key;

            if ("EVENT".equals(t.getTriggerType())) {
                key = t.getSourceObjCode() + ":" + t.getEventKey();
                removeTrigger(eventTriggers, key, info);
            } else if ("ATTR".equals(t.getTriggerType())) {
                key = t.getSourceObjCode() + ":" + t.getAttrKey();
                removeTrigger(attrTriggers, key, info);
            }
        }

        log.info("触发器已注销: strategy={}", strategyCode);
    }

    /** 完全清空所有触发器 */
    public void clearAll() {
        eventTriggers.clear();
        attrTriggers.clear();
        strategyTriggerIndex.clear();
        log.info("TriggerListener: 所有触发器已清空");
    }

    private void removeTrigger(Map<String, List<TriggerInfo>> map, String key, TriggerInfo info) {
        List<TriggerInfo> list = map.get(key);
        if (list != null) {
            list.remove(info);
            if (list.isEmpty()) map.remove(key);
        }
    }


    /* ============================================================
     * 触发入口（外部系统调用）
     * ============================================================ */

    /** 外部系统事件上报 → 事件触发 */
    public void onEventReceived(String objCode, String eventKey, Map<String, Object> eventData) {
        String key = objCode + ":" + eventKey;

        List<TriggerInfo> list = eventTriggers.get(key);
        if (list == null || list.isEmpty()) return;

        for (TriggerInfo info : list) {
            OpEnergyStrategyTrigger trigger = info.getTrigger();

            // condition_expr 判断
            if (!checkCondition(trigger, eventData)) continue;

            executeTrigger(info, "EVENT", eventData, "EVENT:" + eventKey);
        }
    }

    /** 外部系统属性变化上报 → 属性触发 */
    public void onAttrChanged(String objCode, String attrKey, Object newVal) {
        String key = objCode + ":" + attrKey;

        List<TriggerInfo> list = attrTriggers.get(key);
        if (list == null || list.isEmpty()) return;

        Map<String, Object> data = new HashMap<>();
        data.put(attrKey, newVal);

        for (TriggerInfo info : list) {
            OpEnergyStrategyTrigger trigger = info.getTrigger();

            if (!checkCondition(trigger, data)) continue;

            executeTrigger(info, "ATTR", data, "ATTR:" + attrKey);
        }
    }

    /* ============================================================
     * 公共方法
     * ============================================================ */

    private boolean checkCondition(OpEnergyStrategyTrigger trigger, Map<String, Object> data) {
        if (trigger.getConditionExpr() == null || trigger.getConditionExpr().isEmpty()) {
            return true;
        }

        try {
            return conditionEvaluator.evaluate(trigger.getConditionExpr(), data);
        } catch (Exception e) {
            log.error("condition_expr 解析失败: {}", trigger.getConditionExpr(), e);
            return false;
        }
    }

    /** 执行策略 */
    private void executeTrigger(TriggerInfo info, String type, Map<String, Object> data, String source) {
        String strategyCode = info.getStrategyCode();

        log.info(">>> 触发策略: strategy={}, type={}, source={}", strategyCode, type, source);

        Map<String, Object> params = new HashMap<>();
        params.put("trigger_type", type);
        params.put("trigger_source", source);
        params.put("trigger_id", info.getTrigger().getId());
        params.put("event_data", data);

        try {
            getStrategyExecutor().executeStrategy(strategyCode, params);
        } catch (Exception e) {
            log.error("触发策略失败: {}", strategyCode, e);
        }
    }

    /* ============================================================
     * Controller 兼容方法（你的控制器中正在使用）
     * ============================================================ */

    /**
     * 属性变化入口（兼容 Controller）
     */
    public int handleAttrChange(String objCode, String attrKey, Object oldValue, Object newValue) {
        String key = objCode + ":" + attrKey;

        List<TriggerInfo> list = attrTriggers.get(key);
        if (list == null || list.isEmpty()) return 0;

        Map<String, Object> eventData = new HashMap<>();
        eventData.put("oldValue", oldValue);
        eventData.put("newValue", newValue);

        int count = 0;
        for (TriggerInfo info : list) {
            OpEnergyStrategyTrigger trigger = info.getTrigger();

            // 条件判断
            if (!checkCondition(trigger, eventData)) continue;

            executeTrigger(info, "ATTR", eventData, "ATTR:" + attrKey);
            count++;
        }

        return count;
    }

    /**
     * 设备事件入口（兼容 Controller）
     */
    public int handleDeviceEvent(String objCode, String eventKey, Map<String, Object> eventData) {
        String key = objCode + ":" + eventKey;
        List<TriggerInfo> list = eventTriggers.get(key);
        if (list == null || list.isEmpty()) return 0;

        int count = 0;
        for (TriggerInfo info : list) {
            OpEnergyStrategyTrigger trigger = info.getTrigger();

            if (!checkCondition(trigger, eventData)) continue;

            executeTrigger(info, "EVENT", eventData, "EVENT:" + eventKey);
            count++;
        }

        return count;
    }

    /**
     * 获取已注册触发器（用于 /scheduler/status 接口）
     */
    public Map<String, Object> getRegisteredTriggers() {
        Map<String, Object> map = new HashMap<>();

        map.put("eventTriggers", eventTriggers.keySet());
        map.put("attrTriggers", attrTriggers.keySet());
        map.put("strategyIndex", strategyTriggerIndex.keySet());

        return map;
    }


    /* ============================================================
     * 内部结构
     * ============================================================ */

    @Data
    private static class TriggerInfo {
        private final String strategyCode;
        private final OpEnergyStrategyTrigger trigger;
    }
}
