package com.ycwl.basic.pipeline.core;

import com.ycwl.basic.pipeline.exception.PipelineException;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * 通用 Pipeline 实现，负责顺序执行 Stage 并支持动态插入。
 */
@Slf4j
public class Pipeline<C extends PipelineContext> {

    private final List<PipelineStage<C>> stages;
    private final String name;

    public Pipeline(String name, List<PipelineStage<C>> stages) {
        this.name = name;
        this.stages = new ArrayList<>(stages);
    }

    public boolean execute(C context) {
        log.info("[{}] Pipeline 开始执行, Stage 数量: {}", name, stages.size());
        long startTime = System.currentTimeMillis();
        int maxStages = 100;
        int executedCount = 0;

        if (context != null) {
            context.beforePipeline();
        }

        try {
            for (int i = 0; i < stages.size(); i++) {
                if (executedCount >= maxStages) {
                    log.error("[{}] Stage 执行数量超过最大限制({}), 可能存在循环依赖", name, maxStages);
                    throw new PipelineException("Stage执行数量超过最大限制,可能存在循环依赖");
                }

                PipelineStage<C> stage = stages.get(i);
                String stageName = stage.getName();

                log.debug("[{}] [{}/{}] 准备执行 Stage: {}", name, i + 1, stages.size(), stageName);

                if (!stage.shouldExecute(context)) {
                    log.debug("[{}] Stage {} 条件不满足,跳过执行", name, stageName);
                    continue;
                }

                long stageStartTime = System.currentTimeMillis();
                StageResult<C> result = stage.execute(context);
                long stageDuration = System.currentTimeMillis() - stageStartTime;
                executedCount++;

                logStageResult(stageName, result, stageDuration);

                if (result.getNextStages() != null && !result.getNextStages().isEmpty()) {
                    List<PipelineStage<C>> nextStages = result.getNextStages();
                    log.info("[{}] Stage {} 动态添加了 {} 个后续 Stage", name, stageName, nextStages.size());

                    for (int j = 0; j < nextStages.size(); j++) {
                        PipelineStage<C> nextStage = nextStages.get(j);
                        stages.add(i + 1 + j, nextStage);
                        log.debug("[{}]   - 插入 Stage: {} 到位置 {}", name, nextStage.getName(), i + 1 + j);
                    }
                }

                if (result.isFailed()) {
                    log.error("[{}] Stage {} 执行失败, Pipeline 终止", name, stageName);
                    return false;
                }
            }

            long totalDuration = System.currentTimeMillis() - startTime;
            log.info("[{}] Pipeline 执行完成, 总 Stage 数: {}, 实际执行: {}, 耗时: {}ms",
                    name, stages.size(), executedCount, totalDuration);

            if (context != null) {
                context.afterPipeline();
            }
            return true;

        } catch (Exception e) {
            log.error("[{}] Pipeline 执行异常", name, e);
            throw new PipelineException("管线执行失败: " + e.getMessage(), e);
        } finally {
            safeCleanup(context);
        }
    }

    private void logStageResult(String stageName, StageResult<C> result, long duration) {
        String statusIcon = switch (result.getStatus()) {
            case SUCCESS -> "✓";
            case SKIPPED -> "○";
            case DEGRADED -> "△";
            case FAILED -> "✗";
        };

        log.info("[{}] {} Stage {} - {} (耗时: {}ms)",
                name, statusIcon, stageName, result.getStatus(), duration);

        if (result.getMessage() != null) {
            log.debug("[{}]   详情: {}", name, result.getMessage());
        }
    }

    public String getName() {
        return name;
    }

    public int getStageCount() {
        return stages.size();
    }

    public List<String> getStageNames() {
        return stages.stream().map(PipelineStage::getName).toList();
    }

    private void safeCleanup(C context) {
        if (context == null) {
            return;
        }
        try {
            context.cleanup();
        } catch (Exception cleanupError) {
            log.warn("[{}] Pipeline 清理失败", name, cleanupError);
        }
    }
}
