package com.ruoyi.ems.task;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.ems.domain.OpEnergyStrategy;
import com.ruoyi.ems.domain.OpEnergyStrategyTrigger;
import com.ruoyi.ems.service.IOpEnergyStrategyService;
import com.ruoyi.ems.service.IOpEnergyStrategyTriggerService;
import com.ruoyi.ems.strategy.PollingMonitorService;
import com.ruoyi.ems.strategy.executor.StrategyExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**
 * 策略调度器（重构版）
 *
 * 核心改动：所有触发配置统一从触发器表读取
 *
 * 触发类型说明：
 * - EVENT: 事件触发，由 StrategyTriggerListener 处理
 * - TIME: 定时触发，从触发器的 condition_expr 读取 CRON
 * - ATTR: 属性变化触发，由 StrategyTriggerListener 处理
 * - POLLING: 轮询触发，由 PollingMonitorService 处理
 *
 * @author lvwenbin
 */
@Slf4j
@Component
public class StrategyScheduler {

    @Autowired
    private IOpEnergyStrategyService strategyService;

    @Autowired
    private IOpEnergyStrategyTriggerService triggerService;

    @Autowired
    private TaskScheduler taskScheduler;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired(required = false)
    private PollingMonitorService pollingMonitorService;

    @Autowired(required = false)
    private StrategyTriggerListener triggerListener;

    private StrategyExecutor strategyExecutor;

    /**
     * 定时任务缓存
     * key: strategyCode:triggerId
     */
    private final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();

    /**
     * 已注册策略
     */
    private final Map<String, OpEnergyStrategy> registeredStrategies = new ConcurrentHashMap<>();

    /**
     * 统计计数
     */
    private int timeTriggerCount = 0;
    private int eventTriggerCount = 0;
    private int attrTriggerCount = 0;
    private int pollingTriggerCount = 0;

    private StrategyExecutor getStrategyExecutor() {
        if (strategyExecutor == null) {
            synchronized (this) {
                if (strategyExecutor == null) {
                    strategyExecutor = applicationContext.getBean(StrategyExecutor.class);
                }
            }
        }
        return strategyExecutor;
    }

    @PostConstruct
    public void init() {
        log.info("====== 策略调度器初始化（重构版） ======");
        loadEnabledStrategies();
    }

    @PreDestroy
    public void destroy() {
        log.info("====== 策略调度器销毁 ======");
        scheduledTasks.values().forEach(future -> future.cancel(true));
        scheduledTasks.clear();
        registeredStrategies.clear();
    }

    /**
     * 加载所有已启用的策略
     */
    public void loadEnabledStrategies() {
        log.info("开始加载已启用的策略...");

        // 清理现有任务
        clearAllTasks();

        // 查询所有已启用的策略
        OpEnergyStrategy query = new OpEnergyStrategy();
        query.setStrategyState(1);
        List<OpEnergyStrategy> strategies = strategyService.selectStrategyList(query);

        log.info("共查询到 {} 个已启用的策略", strategies.size());

        for (OpEnergyStrategy strategy : strategies) {
            try {
                registerStrategy(strategy);
            } catch (Exception e) {
                log.error("注册策略[{}]失败", strategy.getStrategyCode(), e);
            }
        }

        log.info("====== 策略加载完成 ======");
        log.info("  定时触发: {} 个", timeTriggerCount);
        log.info("  事件触发: {} 个", eventTriggerCount);
        log.info("  属性触发: {} 个", attrTriggerCount);
        log.info("  轮询触发: {} 个", pollingTriggerCount);
    }

    /**
     * 清理所有任务
     */
    private void clearAllTasks() {
        scheduledTasks.values().forEach(future -> future.cancel(true));
        scheduledTasks.clear();
        registeredStrategies.clear();
        timeTriggerCount = 0;
        eventTriggerCount = 0;
        attrTriggerCount = 0;
        pollingTriggerCount = 0;

        // 清理触发监听器
        if (triggerListener != null) {
            triggerListener.clearAll();
        }
    }

    /**
     * 注册策略
     * 核心改动：遍历触发器表，根据每个触发器的类型进行注册
     */
    public void registerStrategy(OpEnergyStrategy strategy) {
        String strategyCode = strategy.getStrategyCode();
        log.info("注册策略[{}]: {}", strategyCode, strategy.getStrategyName());

        registeredStrategies.put(strategyCode, strategy);

        // 查询该策略的所有触发器
        List<OpEnergyStrategyTrigger> triggers = triggerService.selectByStrategyCode(strategyCode);

        if (triggers == null || triggers.isEmpty()) {
            log.warn("策略[{}]没有配置触发器", strategyCode);
            return;
        }

        // 遍历触发器，根据类型进行注册
        for (OpEnergyStrategyTrigger trigger : triggers) {
            if (trigger.getEnable() != 1) {
                log.debug("触发器[{}]已禁用，跳过", trigger.getTriggerName());
                continue;
            }

            registerTrigger(strategyCode, trigger);
        }
    }

    /**
     * 注册单个触发器
     */
    private void registerTrigger(String strategyCode, OpEnergyStrategyTrigger trigger) {
        String triggerType = trigger.getTriggerType();
        String triggerName = trigger.getTriggerName();

        log.debug("注册触发器[{}]: type={}, name={}", strategyCode, triggerType, triggerName);

        switch (triggerType) {
            case "TIME":
                registerTimeTrigger(strategyCode, trigger);
                break;

            case "EVENT":
                registerEventTrigger(strategyCode, trigger);
                break;

            case "ATTR":
                registerAttrTrigger(strategyCode, trigger);
                break;

            case "POLLING":
                registerPollingTrigger(strategyCode, trigger);
                break;

            default:
                log.warn("未知的触发器类型: {}", triggerType);
        }
    }

    /**
     * 注册定时触发器
     * 从 condition_expr 中读取 CRON 表达式
     */
    private void registerTimeTrigger(String strategyCode, OpEnergyStrategyTrigger trigger) {
        String cronExpression = parseCronFromCondition(trigger.getConditionExpr());

        if (cronExpression == null || cronExpression.isEmpty()) {
            log.warn("触发器[{}:{}]未配置CRON表达式", strategyCode, trigger.getTriggerName());
            return;
        }

        // 验证 CRON 表达式
        try {
            new CronTrigger(cronExpression);
        } catch (IllegalArgumentException e) {
            log.error("触发器[{}:{}]的CRON表达式[{}]格式错误",
                strategyCode, trigger.getTriggerName(), cronExpression, e);
            return;
        }

        // 构建任务key
        String taskKey = strategyCode + ":TIME:" + trigger.getId();

        // 取消已有任务
        cancelTask(taskKey);

        // 创建定时任务
        final Long triggerId = trigger.getId();
        final String triggerName = trigger.getTriggerName();

        ScheduledFuture<?> future = taskScheduler.schedule(
            () -> executeTimeTrigger(strategyCode, triggerId, triggerName),
            new CronTrigger(cronExpression)
        );

        scheduledTasks.put(taskKey, future);
        timeTriggerCount++;

        log.info("✓ 定时触发器注册成功: strategy={}, trigger={}, cron={}",
            strategyCode, triggerName, cronExpression);
    }

    /**
     * 从 condition_expr 解析 CRON 表达式
     * 支持格式: {"cron":"0 0 8 * * ?"}
     */
    private String parseCronFromCondition(String conditionExpr) {
        if (conditionExpr == null || conditionExpr.isEmpty()) {
            return null;
        }

        try {
            JSONObject condition = JSON.parseObject(conditionExpr);
            return condition.getString("cron");
        } catch (Exception e) {
            log.warn("解析CRON表达式失败: {}", conditionExpr);
            return null;
        }
    }

    /**
     * 执行定时触发
     */
    private void executeTimeTrigger(String strategyCode, Long triggerId, String triggerName) {
        log.info(">>> 定时触发执行: strategy={}, trigger={}", strategyCode, triggerName);

        try {
            Map<String, Object> params = new HashMap<>();
            params.put("trigger_type", "TIME");
            params.put("trigger_source", "SCHEDULER:" + triggerName);
            params.put("trigger_id", triggerId);
            params.put("exec_by", "SYSTEM_SCHEDULER");

            getStrategyExecutor().executeStrategy(strategyCode, params);

        } catch (Exception e) {
            log.error("定时触发策略[{}]执行失败", strategyCode, e);
        }
    }

    /**
     * 注册事件触发器
     */
    private void registerEventTrigger(String strategyCode, OpEnergyStrategyTrigger trigger) {
        if (triggerListener == null) {
            log.warn("TriggerListener未注入，无法注册事件触发器");
            return;
        }

        triggerListener.registerEventTrigger(strategyCode, trigger);
        eventTriggerCount++;

        log.info("✓ 事件触发器注册成功: strategy={}, device={}, event={}",
            strategyCode, trigger.getSourceObjCode(), trigger.getEventKey());
    }

    /**
     * 注册属性变化触发器
     */
    private void registerAttrTrigger(String strategyCode, OpEnergyStrategyTrigger trigger) {
        if (triggerListener == null) {
            log.warn("TriggerListener未注入，无法注册属性触发器");
            return;
        }

        triggerListener.registerAttrTrigger(strategyCode, trigger);
        attrTriggerCount++;

        log.info("✓ 属性触发器注册成功: strategy={}, device={}, attr={}",
            strategyCode, trigger.getSourceObjCode(), trigger.getAttrKey());
    }

    /**
     * 注册轮询触发器
     */
    private void registerPollingTrigger(String strategyCode, OpEnergyStrategyTrigger trigger) {
        if (pollingMonitorService == null) {
            log.warn("PollingMonitorService未注入，无法注册轮询触发器");
            return;
        }

        // 轮询服务需要策略对象
        OpEnergyStrategy strategy = registeredStrategies.get(strategyCode);
        if (strategy != null) {
            pollingMonitorService.registerPollingStrategy(strategy);
            pollingTriggerCount++;

            log.info("✓ 轮询触发器注册成功: strategy={}, device={}, attr={}",
                strategyCode, trigger.getSourceObjCode(), trigger.getAttrKey());
        }
    }

    /**
     * 注销策略
     */
    public void unregisterStrategy(String strategyCode) {
        log.info("注销策略[{}]", strategyCode);

        // 取消所有相关定时任务
        scheduledTasks.entrySet().removeIf(entry -> {
            if (entry.getKey().startsWith(strategyCode + ":")) {
                entry.getValue().cancel(true);
                return true;
            }
            return false;
        });

        // 移除策略信息
        registeredStrategies.remove(strategyCode);

        // 注销轮询监控
        if (pollingMonitorService != null) {
            pollingMonitorService.unregisterPollingStrategy(strategyCode);
        }

        // 注销事件/属性触发
        if (triggerListener != null) {
            triggerListener.unregisterTriggers(strategyCode);
        }
    }

    /**
     * 刷新策略配置
     */
    public void refreshStrategy(String strategyCode) {
        log.info("刷新策略[{}]", strategyCode);

        // 先注销
        unregisterStrategy(strategyCode);

        // 重新查询并注册
        OpEnergyStrategy strategy = strategyService.selectStrategyByCode(strategyCode);
        if (strategy != null && strategy.getStrategyState() == 1) {
            registerStrategy(strategy);
        }
    }

    /**
     * 取消指定任务
     */
    private void cancelTask(String taskKey) {
        ScheduledFuture<?> future = scheduledTasks.remove(taskKey);
        if (future != null) {
            future.cancel(true);
        }
    }

    // ==================== 统计方法 ====================

    public int getRegisteredCount() {
        return registeredStrategies.size();
    }

    public int getScheduledTaskCount() {
        return scheduledTasks.size();
    }

    public int getAttrTriggerCount() {
        return attrTriggerCount;
    }

    public Map<String, Object> getStatus() {
        Map<String, Object> status = new HashMap<>();
        status.put("registeredStrategies", registeredStrategies.size());
        status.put("timeTriggers", timeTriggerCount);
        status.put("eventTriggers", eventTriggerCount);
        status.put("attrTriggers", attrTriggerCount);
        status.put("pollingTriggers", pollingTriggerCount);
        status.put("scheduledTasks", scheduledTasks.keySet());
        return status;
    }
}