/**
 * PhasePipeline - Phase 간 대기 시간 제거를 위한 파이프라인 시스템
 *
 * 핵심 기능:
 * 1. 현재 Phase 실행 중 다음 Phase 준비 (background)
 * 2. Phase 완료 시 즉시 다음 Phase 시작 (no wait)
 * 3. Phase 실패 시 파이프라인 중단
 */
import { startIteration, startPhase, completePhase, failPhase, completeIteration, formatPhaseStart, formatPhaseComplete, formatIterationComplete } from '../lib/IterationTracker.js';
import { PipelineTimeoutError } from './BackgroundManager.js';
import { CONCURRENCY } from '../lib/constants.js';
import { warnLog } from '../lib/utils.js';
import { initProgress, updatePhase as updateProgressPhase, writeProgressText, } from '../lib/IterationTracker.js';
import { PhaseResultStore } from './PhaseResultStore.js';
import { CheckpointManager } from './CheckpointManager.js';
// ============================================
// PhasePipeline Class
// ============================================
export class PhasePipeline {
    featureName;
    stages = [];
    options;
    abortController;
    backgroundPreparations = new Map();
    resultStore = null;
    checkpointManager = null;
    constructor(featureName, options = {}) {
        this.featureName = featureName;
        this.options = {
            ultrawork: options.ultrawork ?? false,
            maxRetries: options.maxRetries ?? 3,
            timeout: options.timeout ?? CONCURRENCY.PIPELINE_TIMEOUT,
            projectRoot: options.projectRoot ?? '',
            onPhaseComplete: options.onPhaseComplete ?? (() => { }),
            onPhaseStart: options.onPhaseStart ?? (() => { }),
            onError: options.onError ?? (() => { }),
            resultStore: options.resultStore ?? false,
            checkpoints: options.checkpoints ?? [],
            resumeFrom: options.resumeFrom ?? 0,
            onCheckpointPause: options.onCheckpointPause ?? (() => { }),
        };
        this.abortController = new AbortController();
        // Initialize result store if enabled
        if (this.options.resultStore && this.options.projectRoot) {
            this.resultStore = new PhaseResultStore(this.options.projectRoot, featureName);
        }
        // Initialize checkpoint manager if gates provided
        if (this.options.checkpoints.length > 0) {
            this.checkpointManager = new CheckpointManager(this.options.checkpoints, {
                ultrawork: this.options.ultrawork,
                storeDir: this.resultStore?.getStoreDir(),
            });
        }
    }
    /** 스테이지 추가 */
    addStage(stage) {
        this.stages.push(stage);
        return this;
    }
    /** 여러 스테이지 추가 */
    addStages(stages) {
        this.stages.push(...stages);
        return this;
    }
    /** 파이프라인 실행 */
    async execute() {
        const startTime = Date.now();
        const results = [];
        let lastContext = null;
        // Determine start phase (for resume support)
        const resumeFrom = this.options.resumeFrom || 0;
        let startIndex = 0;
        // Load previous results when resuming
        if (resumeFrom > 0 && this.resultStore) {
            const savedResults = this.resultStore.loadAll();
            for (const saved of savedResults) {
                if (saved.phaseNumber < resumeFrom) {
                    results.push(saved.result);
                }
            }
            startIndex = resumeFrom - 1; // 0-based index
            warnLog(`[Pipeline] Resuming from phase ${resumeFrom} (${results.length} previous results loaded)`);
        }
        // 타임아웃 설정
        const timeoutId = setTimeout(() => {
            this.abortController.abort();
        }, this.options.timeout);
        try {
            // Iteration 시작
            const phaseNames = this.stages.map(s => s.name);
            const iteration = startIteration(this.featureName, phaseNames, this.options.ultrawork, this.options.maxRetries);
            // Progress 파일 초기화 (projectRoot가 설정된 경우)
            if (this.options.projectRoot) {
                try {
                    initProgress(this.options.projectRoot, this.featureName, '', phaseNames);
                    writeProgressText(this.options.projectRoot);
                }
                catch { /* progress 파일 실패는 무시 */ }
            }
            // ULTRAWORK 모드: 다음 phase 1개만 미리 준비한다 (B-6).
            // 이전에는 시작 시 미래 phase 전부를 speculative 실행해, 앞 phase 가 성공하기도
            // 전에 token 을 소비하고 실패/취소 시에도 정리되지 않았다. 이제는 각 phase 실행 직전
            // 다음 phase 만 준비하고, abortController.signal 로 취소 가능하다.
            // Phase 순차 실행 (startIndex부터)
            for (let i = startIndex; i < this.stages.length; i++) {
                if (this.abortController.signal.aborted) {
                    throw new PipelineTimeoutError(this.options.timeout);
                }
                const stage = this.stages[i];
                const phaseNumber = i + 1;
                // Phase 시작
                const phaseProgress = startPhase(phaseNumber);
                if (!phaseProgress) {
                    throw new Error(`Failed to start phase ${phaseNumber}`);
                }
                this.options.onPhaseStart(phaseProgress);
                console.log(formatPhaseStart(phaseNumber, stage.name, this.stages.length));
                // Progress 파일 업데이트
                if (this.options.projectRoot) {
                    try {
                        updateProgressPhase(this.options.projectRoot, phaseNumber, 'in_progress');
                        writeProgressText(this.options.projectRoot);
                    }
                    catch { /* 무시 */ }
                }
                // 컨텍스트 생성
                let context = {
                    phaseNumber,
                    phaseName: stage.name,
                    data: {},
                    previousResult: results.length > 0 ? results[results.length - 1] : undefined,
                    allPreviousResults: results.length > 0 ? [...results] : undefined,
                    signal: this.abortController.signal,
                };
                // ULTRAWORK: 현재 phase 가 실행되는 동안 "다음 phase 하나"를 미리 준비한다.
                // (한 단계만 앞서가므로 speculative token 소비를 최소화)
                if (this.options.ultrawork) {
                    this.startBackgroundPreparation(phaseNumber + 1);
                }
                // 백그라운드 준비 결과 병합
                if (this.options.ultrawork && this.backgroundPreparations.has(phaseNumber)) {
                    try {
                        const preparedContext = await this.backgroundPreparations.get(phaseNumber);
                        if (preparedContext) {
                            context.preparedData = preparedContext.data;
                        }
                    }
                    catch {
                        // 백그라운드 준비 실패는 무시 (메인 실행에서 처리)
                    }
                }
                // 동기 준비 (백그라운드 준비가 없거나 실패한 경우)
                if (!context.preparedData && stage.prepare) {
                    const preparedContext = await stage.prepare(this.abortController.signal);
                    context.preparedData = preparedContext.data;
                }
                // 메인 실행 (재시도 포함)
                let result = null;
                let lastError = null;
                for (let retry = 0; retry <= this.options.maxRetries; retry++) {
                    try {
                        result = await stage.execute(context);
                        if (result.success)
                            break;
                        lastError = new Error(result.error || 'Stage execution failed');
                    }
                    catch (error) {
                        lastError = error instanceof Error ? error : new Error(String(error));
                        const failResult = failPhase(phaseNumber, lastError.message);
                        if (!failResult?.canRetry)
                            break;
                        warnLog(`[Pipeline] Phase ${phaseNumber} retry ${retry + 1}/${this.options.maxRetries}`);
                    }
                }
                if (!result || !result.success) {
                    const error = lastError || new Error('Unknown error');
                    this.options.onError(phaseProgress, error);
                    // Progress 파일 업데이트 (blocked)
                    if (this.options.projectRoot) {
                        try {
                            updateProgressPhase(this.options.projectRoot, phaseNumber, 'blocked', [error.message]);
                            writeProgressText(this.options.projectRoot);
                        }
                        catch { /* 무시 */ }
                    }
                    // 정리 실행
                    if (stage.cleanup) {
                        await stage.cleanup(context).catch(() => { });
                    }
                    // 파이프라인 중단 — 진행 중인 다음 phase 준비(speculative)를 취소한다 (B-6)
                    this.abortController.abort();
                    completeIteration();
                    clearTimeout(timeoutId);
                    return {
                        success: false,
                        featureName: this.featureName,
                        totalPhases: this.stages.length,
                        completedPhases: i,
                        failedPhase: phaseNumber,
                        totalDuration: Date.now() - startTime,
                        results,
                        error: error.message,
                    };
                }
                // Phase 완료
                results.push(result);
                completePhase(phaseNumber);
                this.options.onPhaseComplete(phaseProgress, result);
                console.log(formatPhaseComplete(phaseNumber, this.stages.length));
                // Save result to disk (if result store enabled)
                if (this.resultStore) {
                    try {
                        this.resultStore.save(phaseNumber, stage.name, result);
                    }
                    catch {
                        warnLog(`[Pipeline] Failed to save phase ${phaseNumber} result to disk`);
                    }
                }
                // Checkpoint gate check
                if (this.checkpointManager && this.checkpointManager.shouldPause(phaseNumber, result)) {
                    const gate = this.checkpointManager.getGate(phaseNumber);
                    if (gate) {
                        this.options.onCheckpointPause(phaseNumber, gate);
                    }
                    // Progress 파일 업데이트
                    if (this.options.projectRoot) {
                        try {
                            updateProgressPhase(this.options.projectRoot, phaseNumber, 'completed');
                            writeProgressText(this.options.projectRoot);
                        }
                        catch { /* 무시 */ }
                    }
                    completeIteration();
                    clearTimeout(timeoutId);
                    return {
                        success: false,
                        featureName: this.featureName,
                        totalPhases: this.stages.length,
                        completedPhases: i + 1,
                        totalDuration: Date.now() - startTime,
                        results,
                        pausedAtCheckpoint: phaseNumber,
                    };
                }
                // Progress 파일 업데이트 (completed)
                if (this.options.projectRoot) {
                    try {
                        updateProgressPhase(this.options.projectRoot, phaseNumber, 'completed');
                        writeProgressText(this.options.projectRoot);
                    }
                    catch { /* 무시 */ }
                }
                // 정리 실행
                if (stage.cleanup) {
                    await stage.cleanup(context).catch(() => { });
                }
                lastContext = context;
                // 다음 Phase 백그라운드 준비 시작 (아직 안 했으면)
                if (this.options.ultrawork && i + 2 <= this.stages.length) {
                    this.startBackgroundPreparation(i + 2);
                }
            }
            // 완료
            const finalState = completeIteration();
            if (finalState) {
                console.log(formatIterationComplete(finalState));
            }
            clearTimeout(timeoutId);
            return {
                success: true,
                featureName: this.featureName,
                totalPhases: this.stages.length,
                completedPhases: this.stages.length,
                totalDuration: Date.now() - startTime,
                results,
            };
        }
        catch (error) {
            clearTimeout(timeoutId);
            completeIteration();
            const errorMessage = error instanceof Error ? error.message : String(error);
            return {
                success: false,
                featureName: this.featureName,
                totalPhases: this.stages.length,
                completedPhases: results.length,
                totalDuration: Date.now() - startTime,
                results,
                error: errorMessage,
            };
        }
    }
    /** 파이프라인 취소 */
    cancel() {
        this.abortController.abort();
    }
    /** 특정 Phase 백그라운드 준비 시작 (다음 phase 1개만 — B-6) */
    startBackgroundPreparation(phaseNumber) {
        if (this.abortController.signal.aborted)
            return;
        if (this.backgroundPreparations.has(phaseNumber))
            return;
        const stageIndex = phaseNumber - 1;
        if (stageIndex >= this.stages.length)
            return;
        const stage = this.stages[stageIndex];
        if (!stage.prepare)
            return;
        const signal = this.abortController.signal;
        const preparation = (async () => {
            const context = {
                phaseNumber,
                phaseName: stage.name,
                data: {},
                signal,
            };
            try {
                const prepared = await stage.prepare(signal);
                context.data = prepared.data;
                context.preparedData = prepared.data;
            }
            catch (error) {
                warnLog(`[Pipeline] Background preparation for phase ${phaseNumber} failed: ${error}`);
            }
            return context;
        })();
        this.backgroundPreparations.set(phaseNumber, preparation);
    }
}
// ============================================
// Helper Functions
// ============================================
/**
 * 간단한 스테이지 생성 헬퍼
 */
export function createStage(name, execute, options) {
    return {
        name,
        execute,
        prepare: options?.prepare,
        cleanup: options?.cleanup,
    };
}
/**
 * 파이프라인 생성 헬퍼
 */
export function createPipeline(featureName, stages, options) {
    const pipeline = new PhasePipeline(featureName, options);
    pipeline.addStages(stages);
    return pipeline;
}
/**
 * ULTRAWORK 파이프라인 생성 (권장)
 */
export function createUltraworkPipeline(featureName, stages, options) {
    return createPipeline(featureName, stages, { ...options, ultrawork: true });
}
// ============================================
// ToolResult Integration
// ============================================
/**
 * 파이프라인 결과를 ToolResult로 변환
 */
export function pipelineResultToToolResult(result) {
    let text = `## Pipeline: ${result.featureName}\n\n`;
    text += `Status: ${result.success ? '✅ Success' : '❌ Failed'}\n`;
    text += `Phases: ${result.completedPhases}/${result.totalPhases}\n`;
    text += `Duration: ${(result.totalDuration / 1000).toFixed(1)}s\n\n`;
    if (result.error) {
        text += `Error: ${result.error}\n`;
        if (result.failedPhase) {
            text += `Failed at: Phase ${result.failedPhase}\n`;
        }
    }
    text += `\n### Phase Results\n`;
    result.results.forEach((r, i) => {
        const icon = r.success ? '✅' : '❌';
        text += `${icon} Phase ${i + 1}: ${(r.duration / 1000).toFixed(1)}s\n`;
    });
    return {
        content: [{ type: 'text', text }],
        pipelineResult: result,
    };
}
//# sourceMappingURL=PhasePipeline.js.map