package com.ruoyi.ems.strategy.executor;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.ems.domain.EmsObjAttrValue;
import com.ruoyi.ems.domain.OpEnergyStrategyStep;
import com.ruoyi.ems.domain.StrategyExecutionContext;
import com.ruoyi.ems.service.IEmsObjAttrValueService;
import com.ruoyi.ems.service.IOpEnergyStrategyStepService;
import com.ruoyi.ems.service.IStepExecutor;
import com.ruoyi.ems.strategy.evaluator.ConditionEvaluator;
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.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 循环执行器
 * 支持两种跳出条件模式：
 * 1. ATTR - 属性监测模式：实时查询设备属性，满足条件时跳出
 * 2. EXPR - 表达式模式：基于上下文变量判断（旧模式）
 */
@Slf4j
@Component
public class LoopStepExecutor implements IStepExecutor {

    @Autowired
    private IOpEnergyStrategyStepService stepService;

    @Autowired
    private ConditionEvaluator conditionEvaluator;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired(required = false)
    private IEmsObjAttrValueService attrValueService;

    private StepExecutorFactory stepExecutorFactory;

    private StepExecutorFactory getStepExecutorFactory() {
        if (stepExecutorFactory == null) {
            stepExecutorFactory = applicationContext.getBean(StepExecutorFactory.class);
        }
        return stepExecutorFactory;
    }

    @Override
    public Object execute(OpEnergyStrategyStep step, StrategyExecutionContext context) throws Exception {
        int maxCount = step.getLoopMaxCount() != null ? step.getLoopMaxCount() : 0;
        int interval = step.getLoopInterval() != null ? step.getLoopInterval() : 1000;
        String loopCondition = step.getLoopCondition();

        LoopBreakConfig breakConfig = parseBreakConfig(loopCondition);

        log.info("循环步骤[{}]开始执行: maxCount={}, interval={}ms, breakType={}, breakConfig={}",
            step.getStepCode(),
            maxCount == 0 ? "无限" : maxCount,
            interval,
            breakConfig.breakType,
            breakConfig);

        // 加载子步骤
        List<OpEnergyStrategyStep> childSteps = stepService.selectStepsByParentCode(
                step.getStrategyCode(), step.getStepCode()
            ).stream()
            .filter(s -> s.getEnable() == 1)
            .sorted(Comparator.comparingInt(OpEnergyStrategyStep::getStepIndex))
            .collect(Collectors.toList());

        if (childSteps.isEmpty()) {
            log.warn("循环步骤[{}]没有子步骤，跳过执行", step.getStepCode());
            return "循环步骤无子步骤";
        }

        int loopCount = 0;
        boolean shouldBreak = false;
        String breakReason = "";

        // 循环执行
        while (true) {
            loopCount++;
            log.debug("循环步骤[{}]第{}次执行开始", step.getStepCode(), loopCount);

            // 执行所有子步骤
            for (OpEnergyStrategyStep childStep : childSteps) {
                if (!executeChildStep(childStep, context)) {
                    log.error("循环步骤[{}]中的子步骤[{}]执行失败，终止循环",
                        step.getStepCode(), childStep.getStepCode());
                    shouldBreak = true;
                    breakReason = "子步骤执行失败";
                    break;
                }
            }

            if (shouldBreak) {
                break;
            }

            BreakCheckResult checkResult = checkBreakCondition(breakConfig, context);
            if (checkResult.shouldBreak) {
                log.info("循环步骤[{}]满足跳出条件，退出循环（共执行{}次）。原因: {}",
                    step.getStepCode(), loopCount, checkResult.reason);
                breakReason = checkResult.reason;
                break;
            }

            // 检查最大循环次数
            if (maxCount > 0 && loopCount >= maxCount) {
                log.info("循环步骤[{}]达到最大循环次数{}，退出循环",
                    step.getStepCode(), maxCount);
                breakReason = "达到最大循环次数";
                break;
            }

            // 等待下一次循环
            if (interval > 0) {
                Thread.sleep(interval);
            }
        }

        String resultMsg = String.format("循环完成，共执行%d次，退出原因: %s", loopCount, breakReason);
        log.info("循环步骤[{}]执行完成: {}", step.getStepCode(), resultMsg);

        return resultMsg;
    }

    /**
     * 解析跳出条件配置
     */
    private LoopBreakConfig parseBreakConfig(String loopCondition) {
        LoopBreakConfig config = new LoopBreakConfig();

        if (loopCondition == null || loopCondition.trim().isEmpty()) {
            config.breakType = "NONE";
            return config;
        }

        try {
            JSONObject condition = JSON.parseObject(loopCondition);

            // 新格式：属性监测模式
            if ("ATTR".equals(condition.getString("breakType"))) {
                config.breakType = "ATTR";
                config.deviceCode = condition.getString("deviceCode");
                config.modelCode = condition.getString("modelCode");
                config.attrKey = condition.getString("attrKey");
                config.operator = condition.getString("operator");
                config.value = condition.getString("value");

                log.debug("解析到属性监测跳出条件: device={}, attr={}, op={}, value={}",
                    config.deviceCode, config.attrKey, config.operator, config.value);
            }
            // 表达式模式
            else if (condition.containsKey("left") || condition.containsKey("logic")) {
                config.breakType = "EXPR";
                config.expression = loopCondition;
            }
            else {
                config.breakType = "EXPR";
                config.expression = loopCondition;
            }

        } catch (Exception e) {
            log.warn("解析跳出条件失败，使用表达式模式: {}", loopCondition);
            config.breakType = "EXPR";
            config.expression = loopCondition;
        }

        return config;
    }

    /**
     * 检查跳出条件（核心方法）
     */
    private BreakCheckResult checkBreakCondition(LoopBreakConfig config, StrategyExecutionContext context) {
        BreakCheckResult result = new BreakCheckResult();
        result.shouldBreak = false;

        if ("NONE".equals(config.breakType)) {
            return result;
        }

        // 属性监测模式：实时查询设备属性
        if ("ATTR".equals(config.breakType)) {
            return checkAttrBreakCondition(config, context);
        }

        // 表达式模式：基于上下文变量判断
        if ("EXPR".equals(config.breakType)) {
            return checkExprBreakCondition(config, context);
        }

        return result;
    }

    /**
     * 属性监测模式：实时查询设备属性并判断
     */
    private BreakCheckResult checkAttrBreakCondition(LoopBreakConfig config, StrategyExecutionContext context) {
        BreakCheckResult result = new BreakCheckResult();
        result.shouldBreak = false;

        if (attrValueService == null) {
            log.warn("属性值服务未注入，无法使用属性监测模式");
            return result;
        }

        if (config.deviceCode == null || config.attrKey == null) {
            log.warn("属性监测配置不完整: deviceCode={}, attrKey={}", config.deviceCode, config.attrKey);
            return result;
        }

        try {
            // 实时查询设备属性值
            EmsObjAttrValue attrValue = attrValueService.selectObjAttrValue(
                config.modelCode,
                config.deviceCode,
                config.attrKey
            );

            log.debug("实时查询属性值: device={}, attr={}, value={}",
                config.deviceCode, config.attrKey, attrValue.getAttrValue());

            // 将查询到的值同步到上下文（供子步骤使用）
            String contextKey = "current_" + config.attrKey;
            context.setVariable(contextKey, attrValue.getAttrValue());

            // 比较属性值是否满足跳出条件
            boolean conditionMet = compareValue(attrValue.getAttrValue(), config.operator, config.value);

            if (conditionMet) {
                result.shouldBreak = true;
                result.reason = String.format("设备[%s]的属性[%s]值为[%s]，满足条件[%s %s]",
                    config.deviceCode, config.attrKey, attrValue.getAttrValue(), config.operator, config.value);
            }

        } catch (Exception e) {
            log.error("查询设备属性失败: device={}, attr={}", config.deviceCode, config.attrKey, e);
        }

        return result;
    }

    /**
     * 表达式模式：基于上下文变量判断
     */
    private BreakCheckResult checkExprBreakCondition(LoopBreakConfig config, StrategyExecutionContext context) {
        BreakCheckResult result = new BreakCheckResult();
        result.shouldBreak = false;

        if (config.expression == null || config.expression.trim().isEmpty()) {
            return result;
        }

        try {
            boolean conditionMet = conditionEvaluator.evaluate(config.expression, context.getVariables());

            if (conditionMet) {
                result.shouldBreak = true;
                result.reason = "表达式条件满足: " + config.expression;
            }
        } catch (Exception e) {
            log.error("评估表达式条件失败: {}", config.expression, e);
        }

        return result;
    }

    /**
     * 比较值是否满足条件
     */
    private boolean compareValue(Object actual, String operator, String expected) {
        if (actual == null) {
            return false;
        }

        // 统一转为字符串比较（去除小数点后的0）
        String actualStr = String.valueOf(actual).replaceAll("\\.0+$", "").trim();
        String expectedStr = String.valueOf(expected).replaceAll("\\.0+$", "").trim();

        log.debug("比较值: actual=[{}], operator=[{}], expected=[{}]", actualStr, operator, expectedStr);

        switch (operator) {
            case "==":
            case "equals":
                return actualStr.equals(expectedStr);

            case "!=":
            case "notEquals":
                return !actualStr.equals(expectedStr);

            case ">":
                return compareNumeric(actual, expected) > 0;

            case ">=":
                return compareNumeric(actual, expected) >= 0;

            case "<":
                return compareNumeric(actual, expected) < 0;

            case "<=":
                return compareNumeric(actual, expected) <= 0;

            default:
                log.warn("未知的比较运算符: {}", operator);
                return false;
        }
    }

    /**
     * 数值比较
     */
    private int compareNumeric(Object a, Object b) {
        try {
            double va = Double.parseDouble(String.valueOf(a));
            double vb = Double.parseDouble(String.valueOf(b));
            return Double.compare(va, vb);
        } catch (NumberFormatException e) {
            log.warn("数值比较失败: {} vs {}", a, b);
            return 0;
        }
    }

    /**
     * 执行子步骤
     */
    private boolean executeChildStep(OpEnergyStrategyStep childStep, StrategyExecutionContext context) {
        try {
            // 评估子步骤的执行条件
            if (childStep.getConditionExpr() != null && !childStep.getConditionExpr().isEmpty()) {
                boolean conditionMet = conditionEvaluator.evaluate(
                    childStep.getConditionExpr(), context.getVariables()
                );
                if (!conditionMet) {
                    log.debug("子步骤[{}]条件不满足，跳过", childStep.getStepCode());
                    return true;
                }
            }

            IStepExecutor executor = getStepExecutorFactory().getExecutor(childStep.getStepType());
            Object result = executor.execute(childStep, context);
            context.setStepResult(childStep.getStepCode(), result);

            return true;

        } catch (Exception e) {
            log.error("子步骤[{}]执行失败", childStep.getStepCode(), e);

            if (childStep.getContinueOnFail() == 1) {
                log.warn("子步骤[{}]执行失败，但继续执行", childStep.getStepCode());
                return true;
            } else {
                return false;
            }
        }
    }

    @Override
    public String getSupportedType() {
        return "LOOP";
    }

    /**
     * 跳出条件配置
     */
    private static class LoopBreakConfig {
        String breakType = "NONE"; // NONE, ATTR, EXPR

        // ATTR 模式配置
        String deviceCode;
        String modelCode;
        String attrKey;
        String operator;
        String value;

        // EXPR 模式配置
        String expression;

        @Override
        public String toString() {
            if ("ATTR".equals(breakType)) {
                return String.format("ATTR[device=%s, attr=%s, op=%s, value=%s]",
                    deviceCode, attrKey, operator, value);
            } else if ("EXPR".equals(breakType)) {
                return String.format("EXPR[%s]", expression);
            }
            return "NONE";
        }
    }

    /**
     * 跳出检查结果
     */
    private static class BreakCheckResult {
        boolean shouldBreak;
        String reason = "";
    }
}