package com.ruoyi.ems.strategy.executor;

import com.ruoyi.ems.domain.OpEnergyStrategyStep;
import com.ruoyi.ems.domain.StrategyExecutionContext;
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.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 并行执行器（修复版）
 *
 * @author lvwenbin
 */
@Slf4j
@Component
public class ParallelStepExecutor implements IStepExecutor {

    @Autowired
    private IOpEnergyStrategyStepService stepService;

    @Autowired
    private ConditionEvaluator conditionEvaluator;

    @Autowired
    private ApplicationContext applicationContext;

    private StepExecutorFactory stepExecutorFactory;

    /**
     * 并行执行线程池
     * 修复：使用固定大小线程池，避免资源耗尽
     */
    private final ExecutorService parallelExecutor = Executors.newFixedThreadPool(10);

    /**
     * 默认超时时间（秒）
     */
    private static final int DEFAULT_TIMEOUT = 60;

    /**
     * 获取 StepExecutorFactory（延迟加载，避免循环依赖）
     */
    private StepExecutorFactory getStepExecutorFactory() {
        if (stepExecutorFactory == null) {
            synchronized (this) {
                if (stepExecutorFactory == null) {
                    stepExecutorFactory = applicationContext.getBean(StepExecutorFactory.class);
                }
            }
        }
        return stepExecutorFactory;
    }

    @Override
    public Object execute(OpEnergyStrategyStep step, StrategyExecutionContext context) throws Exception {
        String stepCode = step.getStepCode();
        String strategyCode = step.getStrategyCode();

        log.info("========== 并行步骤[{}]开始执行 ==========", stepCode);
        log.info("并行步骤信息: strategyCode={}, stepName={}, parentStepCode={}",
            strategyCode, step.getStepName(), step.getParentStepCode());

        // 1. 查询所有子步骤
        List<OpEnergyStrategyStep> childSteps = stepService.selectStepsByParentCode(strategyCode, stepCode);

        // 【关键修复1】增加详细日志，确认查询结果
        log.info("并行步骤[{}]查询子步骤: strategyCode={}, parentStepCode={}", stepCode, strategyCode, stepCode);

        if (childSteps == null) {
            log.warn("并行步骤[{}]子步骤查询返回null，可能是Service方法问题", stepCode);
            childSteps = new ArrayList<>();
        }

        log.info("并行步骤[{}]查询到{}个子步骤（过滤前）", stepCode, childSteps.size());

        // 打印所有查询到的子步骤
        for (OpEnergyStrategyStep child : childSteps) {
            log.info("  - 子步骤: code={}, name={}, type={}, enable={}, parentCode={}",
                child.getStepCode(), child.getStepName(), child.getStepType(),
                child.getEnable(), child.getParentStepCode());
        }

        // 过滤启用的步骤并排序
        childSteps = childSteps.stream()
            .filter(s -> {
                boolean enabled = s.getEnable() != null && s.getEnable() == 1;
                if (!enabled) {
                    log.info("  - 子步骤[{}]已禁用，跳过", s.getStepCode());
                }
                return enabled;
            })
            .sorted(Comparator.comparingInt(s -> s.getStepIndex() != null ? s.getStepIndex() : 0))
            .collect(Collectors.toList());

        log.info("并行步骤[{}]过滤后有{}个启用的子步骤", stepCode, childSteps.size());

        if (childSteps.isEmpty()) {
            log.warn("并行步骤[{}]没有启用的子步骤，跳过执行", stepCode);
            return buildResult(true, "并行步骤无启用的子步骤", new ArrayList<>());
        }

        log.info("并行步骤[{}]将并行执行{}个子步骤: {}",
            stepCode,
            childSteps.size(),
            childSteps.stream().map(s -> s.getStepName() + "(" + s.getStepCode() + ")").collect(Collectors.joining(", ")));

        // 2. 并行执行所有子步骤
        List<CompletableFuture<ChildStepResult>> futures = new ArrayList<>();

        // 【关键修复2】为每个子步骤创建独立的Future，并增加异常处理
        for (int i = 0; i < childSteps.size(); i++) {
            final OpEnergyStrategyStep childStep = childSteps.get(i);
            final int index = i;

            log.info("并行步骤[{}]创建子步骤任务[{}/{}]: {}",
                stepCode, index + 1, childSteps.size(), childStep.getStepCode());

            CompletableFuture<ChildStepResult> future = CompletableFuture.supplyAsync(() -> {
                log.info(">>> 并行子任务[{}]开始执行: {}", index + 1, childStep.getStepCode());
                ChildStepResult result = executeChildStep(childStep, context, index + 1);
                log.info("<<< 并行子任务[{}]执行完成: {} - {}",
                    index + 1, childStep.getStepCode(), result.success ? "成功" : "失败");
                return result;
            }, parallelExecutor).exceptionally(ex -> {
                // 【关键修复3】捕获异步执行中的异常
                log.error("并行子任务[{}]执行异常: {}", index + 1, childStep.getStepCode(), ex);
                return new ChildStepResult(
                    childStep.getStepCode(),
                    childStep.getStepName(),
                    false,
                    null,
                    "异步执行异常: " + ex.getMessage()
                );
            });

            futures.add(future);
        }

        log.info("并行步骤[{}]已创建{}个并行任务，等待执行完成...", stepCode, futures.size());

        // 3. 等待所有子步骤完成
        int timeout = step.getTimeout() != null ? step.getTimeout() : DEFAULT_TIMEOUT;

        try {
            CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                futures.toArray(new CompletableFuture[0])
            );

            // 等待所有任务完成（带超时）
            allFutures.get(timeout, TimeUnit.SECONDS);
            log.info("并行步骤[{}]所有子任务执行完成", stepCode);

        } catch (java.util.concurrent.TimeoutException e) {
            log.error("并行步骤[{}]等待超时({}秒)", stepCode, timeout);
        } catch (Exception e) {
            log.error("并行步骤[{}]等待子步骤完成时发生异常", stepCode, e);
        }

        // 4. 收集执行结果
        List<ChildStepResult> results = new ArrayList<>();
        int successCount = 0;
        int failCount = 0;

        for (int i = 0; i < futures.size(); i++) {
            CompletableFuture<ChildStepResult> future = futures.get(i);
            OpEnergyStrategyStep childStep = childSteps.get(i);

            try {
                if (future.isDone()) {
                    ChildStepResult result = future.get();
                    results.add(result);

                    if (result.success) {
                        successCount++;
                        // 保存结果到上下文
                        context.setStepResult(childStep.getStepCode(), result.result);
                        log.info("并行子步骤[{}]执行成功", childStep.getStepCode());
                    } else {
                        failCount++;
                        log.warn("并行子步骤[{}]执行失败: {}", childStep.getStepCode(), result.errorMessage);
                    }
                } else {
                    // 超时未完成
                    log.warn("并行子步骤[{}]执行超时", childStep.getStepCode());
                    results.add(new ChildStepResult(childStep.getStepCode(), childStep.getStepName(),
                        false, null, "执行超时"));
                    failCount++;

                    // 取消未完成的任务
                    future.cancel(true);
                }
            } catch (Exception e) {
                log.error("并行子步骤[{}]结果收集异常", childStep.getStepCode(), e);
                results.add(new ChildStepResult(childStep.getStepCode(), childStep.getStepName(),
                    false, null, e.getMessage()));
                failCount++;
            }
        }

        // 5. 构建并返回结果
        boolean allSuccess = failCount == 0;
        String message = String.format("并行执行完成: 总数=%d, 成功=%d, 失败=%d",
            childSteps.size(), successCount, failCount);

        log.info("========== 并行步骤[{}]执行完成: {} ==========", stepCode, message);

        return buildResult(allSuccess, message, results);
    }

    /**
     * 执行单个子步骤
     * 【关键修复4】增加更详细的执行日志和异常处理
     */
    private ChildStepResult executeChildStep(OpEnergyStrategyStep childStep,
        StrategyExecutionContext context,
        int taskIndex) {
        String stepCode = childStep.getStepCode();
        String stepName = childStep.getStepName();
        long startTime = System.currentTimeMillis();

        try {
            log.info("[Task-{}] 开始执行子步骤: code={}, name={}, type={}",
                taskIndex, stepCode, stepName, childStep.getStepType());

            // 打印步骤详细信息
            log.info("[Task-{}] 步骤详情: targetObj={}, abilityKey={}, param={}",
                taskIndex,
                childStep.getTargetObjCode(),
                childStep.getAbilityKey(),
                childStep.getAbilityParam());

            // 评估执行条件
            if (childStep.getConditionExpr() != null && !childStep.getConditionExpr().isEmpty()) {
                log.info("[Task-{}] 评估执行条件: {}", taskIndex, childStep.getConditionExpr());
                boolean conditionMet = conditionEvaluator.evaluate(
                    childStep.getConditionExpr(),
                    context.getVariables()
                );
                if (!conditionMet) {
                    log.info("[Task-{}] 子步骤[{}]条件不满足，跳过", taskIndex, stepCode);
                    return new ChildStepResult(stepCode, stepName, true, "条件不满足,已跳过", null);
                }
            }

            // 获取对应的执行器
            log.info("[Task-{}] 获取步骤类型[{}]的执行器", taskIndex, childStep.getStepType());
            IStepExecutor executor = getStepExecutorFactory().getExecutor(childStep.getStepType());

            if (executor == null) {
                log.error("[Task-{}] 未找到步骤类型[{}]的执行器", taskIndex, childStep.getStepType());
                return new ChildStepResult(stepCode, stepName, false, null,
                    "未找到执行器: " + childStep.getStepType());
            }

            // 执行步骤
            log.info("[Task-{}] 调用执行器执行步骤...", taskIndex);
            Object result = executor.execute(childStep, context);

            long duration = System.currentTimeMillis() - startTime;
            log.info("[Task-{}] 子步骤[{}]执行成功, 耗时{}ms, 结果: {}",
                taskIndex, stepCode, duration, result);

            return new ChildStepResult(stepCode, stepName, true, result, null);

        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            log.error("[Task-{}] 子步骤[{}]执行失败, 耗时{}ms", taskIndex, stepCode, duration, e);

            // 检查是否配置了失败继续
            if (childStep.getContinueOnFail() != null && childStep.getContinueOnFail() == 1) {
                log.warn("[Task-{}] 子步骤[{}]执行失败，但配置了失败继续", taskIndex, stepCode);
                return new ChildStepResult(stepCode, stepName, true, null, "失败但继续: " + e.getMessage());
            }

            return new ChildStepResult(stepCode, stepName, false, null, e.getMessage());
        }
    }

    /**
     * 构建执行结果
     */
    private Map<String, Object> buildResult(boolean success, String message, List<ChildStepResult> childResults) {
        Map<String, Object> result = new HashMap<>();
        result.put("success", success);
        result.put("message", message);
        result.put("childResults", childResults);
        result.put("childCount", childResults.size());

        // 统计成功和失败数量
        long successCount = childResults.stream().filter(r -> r.success).count();
        long failCount = childResults.size() - successCount;
        result.put("successCount", successCount);
        result.put("failCount", failCount);

        return result;
    }

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

    /**
     * 子步骤执行结果
     */
    private static class ChildStepResult {
        String stepCode;
        String stepName;
        boolean success;
        Object result;
        String errorMessage;

        ChildStepResult(String stepCode, String stepName, boolean success, Object result, String errorMessage) {
            this.stepCode = stepCode;
            this.stepName = stepName;
            this.success = success;
            this.result = result;
            this.errorMessage = errorMessage;
        }

        @Override
        public String toString() {
            return String.format("{stepCode='%s', stepName='%s', success=%s, error='%s'}",
                stepCode, stepName, success, errorMessage);
        }
    }
}
