import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { createHash } from 'crypto';
import { lockManager } from '../core/lock';
import { actionQueue } from '../core/queue';
import { logInfo, logError } from '../utils';
import { AgentDataValidator, PerformanceProfiler, CognitionAudit } from './diagnostics';
import { WikiFormatter } from './formatter';
import { ErrorType, RecoveryRule } from '../types/interfaces';
export { ErrorType, RecoveryRule };

// ─────────────────────────────────────────────
// 1. 에이전트 인터페이스 확장 (Interface Extensibility)
// ─────────────────────────────────────────────

export type AbstractionLevel = 'laser-focused' | 'balanced' | 'comprehensive';

/**
 * 에이전트 실행 시 전달되는 확장 옵션 객체.
 * 향후 에이전트별로 고유한 설정(temperature, maxTokens 등)을
 * IAgent 시그니처를 변경하지 않고 유연하게 주입할 수 있습니다.
 */
export interface AgentExecuteOptions {
    /** 에이전트 실행의 추가 컨텍스트 문자열 */
    context?: string;
    /** 실행 중단 시그널 */
    signal?: AbortSignal;
    /** 에이전트별 커스텀 설정 (temperature, maxTokens 등) */
    config?: Record<string, unknown>;
    /** 이전 단계의 중간 결과물 (병렬 파이프라인용) */
    priorResults?: Record<string, string | undefined>;
    /** 에이전트 간 정보 전달 시의 추상화/필터링 수준 */
    abstractionLevel?: AbstractionLevel;
}

/**
 * 에이전트 인터페이스 정의 (의존성 주입을 위함).
 * execute()는 기존 시그니처를 유지하면서, 확장 옵션도 수용합니다.
 */
export interface IAgent {
    execute(input: string, context?: string, signal?: AbortSignal, options?: AgentExecuteOptions): Promise<string>;
}

// ─────────────────────────────────────────────
// 2. 상태 관리의 명시적 분리 (Explicit State Management)
// ─────────────────────────────────────────────

/**
 * 파이프라인 단계 상태 정의
 */
export type PipelineStage = 'idle' | 'planner' | 'researcher' | 'reflector' | 'writer' | 'completed' | 'error';

/**
 * 감사(Audit) 이력에 기록되는 단일 상태 전환 엔트리.
 */
export interface AuditEntry {
    from: PipelineStage;
    to: PipelineStage;
    message: string;
    timestamp: number;
    durationFromPrev?: number;
}

/**
 * MissionState: 엔진의 내부 상태를 캡슐화하는 독립 객체.
 * 상태 전환의 모든 이력(Audit Trail)을 자동으로 기록하며,
 * 외부 모니터링 시스템과 연동하여 투명한 파이프라인 추적을 가능하게 합니다.
 */
export class MissionState {
    private _stage: PipelineStage = 'idle';
    private _auditTrail: AuditEntry[] = [];
    private _lastTransitionTime: number = Date.now();
    private _results: Record<string, string> = {};
    private _failureReason?: string;

    public readonly missionId: string;
    public readonly startTime: number;
    public readonly promptHash: string; // [Structural Fix] 정식 필드로 추가
    public resilienceMetrics = {
        fallbacks: 0,
        retries: 0,
        maxConflictScore: 0,
        deduplications: 0
    };

    constructor(missionId: string, promptHash: string = '') {
        this.missionId = missionId;
        this.promptHash = promptHash; // 생성 시점에 즉시 할당
        this.startTime = Date.now();
        this._lastTransitionTime = this.startTime;
    }

    get stage(): PipelineStage {
        return this._stage;
    }

    get auditTrail(): ReadonlyArray<AuditEntry> {
        return this._auditTrail;
    }

    /**
     * 상태를 전환하고, 감사 이력에 자동으로 기록합니다.
     */
    public transition(to: PipelineStage, message: string): void {
        const now = Date.now();
        const entry: AuditEntry = {
            from: this._stage,
            to,
            message,
            timestamp: now,
            durationFromPrev: now - this._lastTransitionTime
        };
        this._auditTrail.push(entry);
        this._stage = to;
        this._lastTransitionTime = now;

        logInfo(`[MissionState] ${this.missionId}: ${entry.from} → ${entry.to} (${entry.durationFromPrev}ms) — ${message}`);
        this.saveToDisk();
    }

    /**
     * 진행 상태를 디스크에 영구적으로 기록합니다 (State Save).
     * 크래시 발생 시 어디까지 진행되었는지 파악하는 기초 데이터가 됩니다.
     */
    private saveToDisk(): void {
        try {
            const workspacePath = process.env.ASTRA_TEST_ROOT || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || process.cwd();

            const astraDir = path.join(workspacePath, '.astra', 'missions');
            if (!fs.existsSync(astraDir)) {
                fs.mkdirSync(astraDir, { recursive: true });
            }
            const filePath = path.join(astraDir, `${this.missionId}.json`);
            fs.writeFileSync(filePath, JSON.stringify(this.toStructuredLog(), null, 2), 'utf-8');
        } catch (err) {
            logError(`[MissionState] Failed to save state to disk for ${this.missionId}`, err);
        }
    }

    public setFailureReason(reason: string): void {
        this._failureReason = reason;
        this.saveToDisk();
    }

    /**
     * 중간 결과물을 저장합니다 (Resumption용).
     */
    public setResult(key: string, value: string): void {
        this._results[key] = value;
        this.saveToDisk();
    }

    public getResult(key: string): string | undefined {
        return this._results[key];
    }

    /**
     * 저장된 미션 상태를 불러옵니다 (Resumption용).
     * 프롬프트 해시를 비교하여 질문이 변경되었을 경우 무효화합니다.
     */
    public static loadFromDisk(missionId: string, currentPrompt: string): MissionState | null {
        try {
            const workspacePath = process.env.ASTRA_TEST_ROOT || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || process.cwd();
            const filePath = path.join(workspacePath, '.astra', 'missions', `${missionId}.json`);
            if (!fs.existsSync(filePath)) return null;

            const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
            
            // [Structural Fix] 프롬프트 무결성 검증
            const currentPromptHash = createHash('sha256').update(currentPrompt).digest('hex').slice(0, 16);
            if (data.promptHash && data.promptHash !== currentPromptHash) {
                logInfo(`[MissionState] 프롬프트 변경 감지. 이전 상태를 폐기하고 새로 시작합니다.`);
                return null;
            }

            const state = new MissionState(missionId, currentPromptHash);
            state._stage = data.status;
            state._results = data.results || {};
            state.resilienceMetrics = data.resilienceMetrics || {
                fallbacks: 0,
                retries: 0,
                maxConflictScore: 0,
                deduplications: 0
            };
            return state;
        } catch (err) {
            return null;
        }
    }



    /**
     * 전체 미션의 경과 시간을 반환합니다.
     */
    public getElapsedMs(): number {
        return Date.now() - this.startTime;
    }

    /**
     * 감사 이력을 요약 문자열로 반환합니다 (디버깅/모니터링 용).
     */
    public summarizeAudit(): string {
        return this._auditTrail
            .map(e => `[${e.from}→${e.to}] ${e.durationFromPrev}ms: ${e.message}`)
            .join('\n');
    }

    /**
     * 감사 이력을 구조화된 JSON 포맷으로 출력합니다.
     * 외부 모니터링 시스템(ELK Stack, Prometheus, Loki 등)과 연동 시
     * 파싱 없이 바로 인제스트할 수 있는 표준 로그 포맷입니다.
     * 
     * 출력 예시:
     * ```json
     * {
     *   "missionId": "mission_1714...",
     *   "status": "completed",
     *   "totalElapsedMs": 12450,
     *   "transitions": [
     *     { "from": "idle", "to": "planner", "durationMs": 0, "message": "...", "ts": "..." }
     *   ]
     * }
     * ```
     */
    public toStructuredLog(): object {
        return {
            missionId: this.missionId,
            status: this._stage,
            startTime: new Date(this.startTime).toISOString(),
            totalElapsedMs: this.getElapsedMs(),
            failureReason: this._failureReason,
            results: this._results,
            promptHash: this.promptHash, // 정식 필드 참조
            transitionCount: this._auditTrail.length,
            transitions: this._auditTrail.map(e => ({
                from: e.from,
                to: e.to,
                durationMs: e.durationFromPrev,
                message: e.message,
                ts: new Date(e.timestamp).toISOString()
            })),
            resilienceMetrics: this.resilienceMetrics
        };
    }
}

// ─────────────────────────────────────────────
// 3. Error Recovery Logic (오류 복구 로직)
// ─────────────────────────────────────────────

/**
 * ┌─────────────────────────────────────────────────────────────────────┐
 * │            Error Recovery Matrix (오류 복구 매트릭스)                 │
 * ├──────────────┬──────────┬──────────┬─────────────────────────────────┤
 * │ Error Type   │ Retries  │ Backoff  │ Action                         │
 * ├──────────────┼──────────┼──────────┼─────────────────────────────────┤
 * │ TRANSIENT    │ 3        │ 1000ms   │ Exponential Backoff 자동 재시도  │
 * │ PERMANENT    │ 0        │ N/A      │ 즉시 중단 + 사용자 안내 메시지    │
 * │ ABORT        │ 0        │ N/A      │ 조용한 종료 (Graceful Exit)      │
 * └──────────────┴──────────┴──────────┴─────────────────────────────────┘
 */
export const ERROR_RECOVERY_MATRIX: ReadonlyArray<RecoveryRule> = [
    {
        type: ErrorType.TRANSIENT,
        description: '네트워크 타임아웃, 일시적 API 지연, 연결 거부 등',
        maxRetries: 3,
        backoffBaseMs: 1000,
        action: 'retry',
        userMessage: '일시적인 연결 문제가 감지되었습니다. 자동으로 재시도 중입니다...'
    },
    {
        type: ErrorType.PERMANENT,
        description: '모델 응답 형식 오류, 프롬프트 구조 문제, 인증 실패 등',
        maxRetries: 0,
        backoffBaseMs: 0,
        action: 'fail_with_message',
        userMessage: '모델 응답에 근본적인 문제가 발생했습니다. 모델 설정을 확인하거나 다른 모델로 변경해 주세요.'
    },
    {
        type: ErrorType.ABORT,
        description: '사용자의 의도적 작업 취소',
        maxRetries: 0,
        backoffBaseMs: 0,
        action: 'abort',
        userMessage: '작업이 취소되었습니다.'
    }
];

/**
 * ErrorClassifier: 에러 객체를 분석하여 유형을 자동 판별합니다.
 */
export class ErrorClassifier {
    /** Transient Error로 분류되는 패턴 */
    private static readonly TRANSIENT_PATTERNS: RegExp[] = [
        /timeout/i,
        /ECONNREFUSED/i,
        /ECONNRESET/i,
        /ETIMEDOUT/i,
        /network/i,
        /fetch failed/i,
        /Failed to fetch/i,
        /503/,               // Service Unavailable
        /502/,               // Bad Gateway
        /500/,               // Internal Server Error (일시적일 수 있음)
        /429/,               // Too Many Requests (Rate Limit)
        /ENOTFOUND/i,
        /socket hang up/i,
        /out of memory/i,    // GPU/System OOM
        /oom/i,
        /failed to allocate/i
    ];

    /** Permanent Error로 분류되는 패턴 */
    private static readonly PERMANENT_PATTERNS: RegExp[] = [
        /401/,               // Unauthorized
        /403/,               // Forbidden
        /404/,               // Not Found (잘못된 모델명 등)
        /유효한 응답을 받지 못했습니다/,
        /Ollama URL이 설정되지 않았습니다/,
        /invalid.*model/i,
        /model.*not found/i,
        /parse error/i,
        /context.*length.*exceeded/i,
        /max.*token.*limit/i,
        /safety.*filter/i,
        /blocked.*content/i
    ];

    /**
     * 에러를 분류하고 해당하는 복구 규칙을 반환합니다.
     */
    public static classify(error: any): { type: ErrorType; rule: RecoveryRule } {
        // 1. Abort 확인
        if (error.name === 'AbortError' || error.message === 'AbortError') {
            return {
                type: ErrorType.ABORT,
                rule: ERROR_RECOVERY_MATRIX.find(r => r.type === ErrorType.ABORT)!
            };
        }

        const message = error.message || String(error);

        // 2. Permanent Error 확인 (우선 순위 높음)
        for (const pattern of this.PERMANENT_PATTERNS) {
            if (pattern.test(message)) {
                return {
                    type: ErrorType.PERMANENT,
                    rule: ERROR_RECOVERY_MATRIX.find(r => r.type === ErrorType.PERMANENT)!
                };
            }
        }

        // 3. Transient Error 확인
        for (const pattern of this.TRANSIENT_PATTERNS) {
            if (pattern.test(message)) {
                return {
                    type: ErrorType.TRANSIENT,
                    rule: ERROR_RECOVERY_MATRIX.find(r => r.type === ErrorType.TRANSIENT)!
                };
            }
        }

        // 4. 분류 불가 → 안전하게 Permanent로 처리 (보수적 접근)
        return {
            type: ErrorType.PERMANENT,
            rule: ERROR_RECOVERY_MATRIX.find(r => r.type === ErrorType.PERMANENT)!
        };
    }
}

/**
 * CacheManager: 중복 수집 방지 (Deduplication)를 위한 캐시 레이어.
 * 동일한 프롬프트와 컨텍스트에 대해 중복된 LLM 호출을 방지합니다.
 */
export class CacheManager {
    private static getCacheDir(): string {
        const workspacePath = process.env.ASTRA_TEST_ROOT || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || process.cwd();
        const cacheDir = path.join(workspacePath, '.astra', 'cache');
        if (!fs.existsSync(cacheDir)) {
            fs.mkdirSync(cacheDir, { recursive: true });
        }
        return cacheDir;
    }

    private static getHash(key: string): string {
        return createHash('sha256').update(key).digest('hex');
    }

    public static get(prompt: string, context: string, currentModel: string = 'unknown'): string | null {
        const key = this.getHash(prompt + context);
        const filePath = path.join(this.getCacheDir(), `${key}.json`); // 확장자 .json으로 변경
        
        if (!fs.existsSync(filePath)) return null;

        try {
            const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
            
            // 1. TTL 검증 (기본 7일)
            const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
            if (Date.now() - data.createdAt > SEVEN_DAYS_MS) {
                logInfo(`[CacheManager] 캐시 만료됨 (TTL 초과).`);
                return null;
            }

            // 2. 모델 버전 검증
            if (data.modelVersion !== currentModel && currentModel !== 'unknown') {
                logInfo(`[CacheManager] 모델 버전 불일치 (${data.modelVersion} -> ${currentModel}). 캐시 스킵.`);
                return null;
            }

            return data.result;
        } catch (err) {
            return null;
        }
    }

    public static set(prompt: string, context: string, result: string, modelVersion: string = 'unknown'): void {
        const key = this.getHash(prompt + context);
        const filePath = path.join(this.getCacheDir(), `${key}.json`);
        const cacheData = {
            result,
            createdAt: Date.now(),
            modelVersion
        };
        fs.writeFileSync(filePath, JSON.stringify(cacheData, null, 2), 'utf-8');
    }
}


// ─────────────────────────────────────────────
// 4. AgentEngine 본체
// ─────────────────────────────────────────────

/**
 * AgentEngine: 
 * Producer-Consumer 패턴을 기반으로 멀티 에이전트 워크플로우를 오케스트레이션하는 핵심 엔진.
 * 명시적 락(Mutex), 의존성 주입(DI), 독립 상태 객체(MissionState),
 * Error Recovery Matrix를 통해 안정성, 유연성, 투명성, 복원력을 동시에 확보합니다.
 * 
 * 아키텍처 특징:
 * - IAgent 인터페이스의 옵션 확장으로 에이전트별 커스텀 설정 지원
 * - MissionState를 통한 감사(Audit) 이력 자동 기록
 * - 병렬 준비 단계(Parallel Prep)를 통한 비동기 흐름 정교화
 * - Error Recovery Matrix 기반의 Transient/Permanent 오류 자동 분류 및 복구
 */
export class AgentEngine {
    constructor(
        private readonly planner: IAgent,
        private readonly researcher: IAgent,
        private readonly writer: IAgent,
        // [Self-Reflection] Researcher와 Writer 사이에 주입되는 메타인지 노드. 미주입 시 기존 3단계 파이프라인을 그대로 유지.
        private readonly reflector?: IAgent
    ) {}

    /**
     * 멀티 에이전트 워크플로우 실행 (Refactored: Atomic State Machine)
     */
    public async runMission(
        missionId: string,
        prompt: string,
        brainContext: string,
        signal: AbortSignal,
        onProgress: (stage: PipelineStage, message: string) => void,
        options?: AgentExecuteOptions
    ): Promise<string> {
        let state: MissionState;
        const promptHash = createHash('sha256').update(prompt).digest('hex').slice(0, 16);

        // 0. 상태 복원 시도 (Resumption) - 프롬프트 무결성 검사 포함
        const existingState = MissionState.loadFromDisk(missionId, prompt);
        state = (existingState && existingState.stage !== 'completed') ? existingState : new MissionState(missionId, promptHash);


        // 1. 명시적 락 획득 (Mutex)
        const release = await lockManager.acquire(`mission_${missionId}`);
        
        try {
            return await actionQueue.enqueue(async () => {
                logInfo(`[AgentEngine] 미션 시작: ${missionId}`);

                // [Structural Fix] 글로벌 캐시 키에 프롬프트 해시 결합 (네임스페이스 분리)
                const globalCacheKey = `global_final_report_${promptHash}`;
                const currentModel = (options?.config?.model as string) || 'unknown';
                const globalCache = CacheManager.get(prompt, globalCacheKey, currentModel);
                if (globalCache) {
                    logInfo(`[AgentEngine] [Deduplication] '${globalCacheKey}' 캐시를 발견했습니다.`);
                    this.transition(state, 'completed', '캐시된 결과 반환', onProgress);
                    return globalCache;
                }

                // --- Phase 1: Planner ---
                const plan = await this.executeStep(
                    state, 'planner', '전략 수립 중...',
                    () => this.resilientExecute(state, this.planner, 'Planner', prompt, brainContext, signal, onProgress, { 
                        ...options, 
                        context: brainContext, 
                        signal, 
                        config: { ...options?.config, role: 'planner', isSamePrompt: true } 
                    }),
                    prompt, brainContext, signal, onProgress
                );

                const plannerScore = this.validateResult(plan, 'Planner');
                // [Structural Fix] 점수가 낮을수록 더 상세한 근거를 요구(comprehensive)하도록 로직 역전
                const researcherLevel: AbstractionLevel = plannerScore < 70 ? 'comprehensive' : 'balanced';

                // --- Phase 2: Researcher ---
                const research = await this.executeStep(
                    state, 'researcher', '핵심 정보 수집 및 분석 중...',
                    () => this.resilientExecute(state, this.researcher, 'Researcher', plan, brainContext, signal, onProgress, { 
                        ...options,
                        context: brainContext, 
                        signal, 
                        config: { ...options?.config, role: 'researcher', isSamePrompt: true }, 
                        abstractionLevel: researcherLevel 
                    }),
                    plan, brainContext, signal, onProgress
                );

                // --- Phase 3: Context Preparation (Side Effect of Phase 2) ---
                let writerPrep = state.getResult('writerPrep');
                if (!writerPrep) {
                    writerPrep = await this.prepareWriterContext(prompt, plan, brainContext);
                    state.setResult('writerPrep', writerPrep);
                }

                const researchScore = this.validateResult(research, 'Researcher');
                // [Structural Fix] 점수가 낮을수록 더 상세한 근거를 요구(comprehensive)하도록 로직 역전
                const writerLevel: AbstractionLevel = researchScore < 65 ? 'comprehensive' : 'balanced';

                // --- Phase 3.5: Reflector (Self-Reflection) ---
                // Reflector가 주입되어 있고 옵션에서 명시적으로 끄지 않은 경우에만 실행한다.
                // 실패해도 파이프라인을 막지 않는다(soft-fail): Reflector는 품질 보강이지 필수 게이트가 아님.
                let reflection = '';
                const reflectionDisabled = options?.config?.enableReflection === false;
                if (this.reflector && !reflectionDisabled) {
                    try {
                        reflection = await this.executeStep(
                            state, 'reflector', '중간 산출물 자기검증 중...',
                            () => this.resilientExecute(state, this.reflector!, 'Reflector', research, brainContext, signal, onProgress, {
                                ...options,
                                context: brainContext,
                                signal,
                                config: { ...options?.config, role: 'reflector', isSamePrompt: true },
                                priorResults: { plan, originalPrompt: prompt, ...options?.priorResults },
                                abstractionLevel: 'balanced'
                            }),
                            // [Cache namespace] Writer와 동일한 (research, prompt) 페어를 쓰면 CacheManager가
                            // Writer 호출 시 reflector 결과를 그대로 반환해버린다. 단계명을 prefix로 분리.
                            `reflector::${research}`, prompt, signal, onProgress
                        );
                    } catch (reflErr: any) {
                        // Reflector 실패는 치명적이지 않다. 감사 이력에만 남기고 빈 reflection으로 Writer를 진행시킨다.
                        if (reflErr?.name === 'AbortError') throw reflErr;
                        logError(`[AgentEngine] Reflector soft-fail — Writer 계속 진행: ${reflErr?.message || reflErr}`);
                        reflection = '';
                    }
                }

                // --- Phase 4: Writer ---
                const finalReport = await this.executeStep(
                    state, 'writer', '최종 리포트 작성 및 편집 중...',
                    () => this.resilientExecute(state, this.writer, 'Writer', research, prompt, signal, onProgress, {
                        ...options,
                        context: brainContext,
                        signal,
                        config: { role: 'writer', allowFallback: true, isSamePrompt: true, ...options?.config },
                        priorResults: { plan, writerPrep, reflection, previousValidData: state.getResult('finalReport'), ...options?.priorResults },
                        abstractionLevel: writerLevel
                    }),
                    research, prompt, signal, onProgress
                );

                state.setResult('finalReport', finalReport);
                
                // --- Phase 5: Advice & Standardization ---
                const proactiveAdvice = await this.generateProactiveAdvice(finalReport, prompt, brainContext, signal);
                
                // [Structural Fix] 생성된 제안의 무결성 검증 (최소 길이 50자 이상일 때만 append)
                const enrichedReport = proactiveAdvice && proactiveAdvice.length > 50
                    ? `${finalReport}\n\n---\n## 💡 Astra의 선제적 제안 (Proactive Next Actions)\n${proactiveAdvice}`
                    : finalReport;

                const standardizedReport = WikiFormatter.format(enrichedReport, state);

                // 최종 결과 전역 캐싱 (Deduplication - Secure Key with Model Awareness)
                CacheManager.set(prompt, `global_final_report_${promptHash}`, standardizedReport, currentModel);

                CognitionAudit.auditPolicyCompliance('MissionComplete', standardizedReport);
                this.transition(state, 'completed', '미션 완료', onProgress);
                return standardizedReport;
            });
        } catch (error: any) {
            this.handleMissionFailure(missionId, state!, error, onProgress);
            throw error;
        } finally {
            release();
        }
    }

    /**
     * [Atomic Step Execution]
     * 개별 작업 단계를 캡슐화하여 상태 확인, 캐시 체크, 실행, 검증을 일관되게 처리합니다.
     */
    private async executeStep(
        state: MissionState,
        stage: PipelineStage,
        progressMessage: string,
        action: () => Promise<string>,
        cacheKeyPrompt: string,
        cacheKeyContext: string,
        signal: AbortSignal,
        onProgress: (stage: PipelineStage, message: string) => void
    ): Promise<string> {
        // 1. 기존 결과 확인 (Resumption)
        let result = state.getResult(stage);
        if (result) {
            logInfo(`[AgentEngine] [Resumption] '${stage}' 단계 결과가 이미 존재합니다.`);
            return result;
        }

        this.transition(state, stage, progressMessage, onProgress);
        this.checkAbort(signal);

        // 2. 캐시 확인 (Deduplication)
        const cached = CacheManager.get(cacheKeyPrompt, cacheKeyContext);
        if (cached) {
            logInfo(`[AgentEngine] [Deduplication] '${stage}' 단계 캐시를 사용합니다.`);
            state.resilienceMetrics.deduplications++;
            result = cached;
        } else {
            // 3. 실행
            result = await action();
            CacheManager.set(cacheKeyPrompt, cacheKeyContext, result);
        }

        // 4. 저장
        state.setResult(stage, result);
        return result;
    }

    private handleMissionFailure(missionId: string, state: MissionState, error: any, onProgress: (stage: PipelineStage, message: string) => void) {
        const { type, rule } = ErrorClassifier.classify(error);
        const stageName = (state.stage || 'unknown').toUpperCase();
        
        this.transition(state, 'error', `오류 발생: ${error.message}`, onProgress);
        state.setFailureReason(`[${type}] ${rule.description} - 세부원인: ${error.message}`);

        logError(`[AgentEngine] [${type}] ${missionId} 실패 at ${stageName} stage: ${error.message}`);
        logError(`[AgentEngine] Audit Trail:\n${state.summarizeAudit()}`);
    }

    /**
     * @deprecated 이제 미션 상태는 로컬 스코프에서 관리됩니다.
     */
    public getMissionState(): MissionState | null {
        return null;
    }


    // ─── Resilience Layer ───

    /**
     * Error Recovery Matrix 기반의 탄력적 에이전트 실행.
     * 
     * - Transient Error: 지수 백오프(Exponential Backoff)를 적용하여 최대 N회 자동 재시도.
     * - Permanent Error: 즉시 중단하고 명확한 사용자 메시지를 첨부하여 예외를 전파.
     * - Abort: 조용하게 예외를 전파 (Graceful Exit).
     */
    private async resilientExecute(
        state: MissionState,
        agent: IAgent,
        agentName: string,
        input: string,
        context: string,
        signal: AbortSignal,
        onProgress: (stage: PipelineStage, message: string) => void,
        options?: AgentExecuteOptions
    ): Promise<string> {
        const transientRule = ERROR_RECOVERY_MATRIX.find(r => r.type === ErrorType.TRANSIENT)!;
        let lastError: any;

        for (let attempt = 0; attempt <= transientRule.maxRetries; attempt++) {
            if (attempt > 0) state.resilienceMetrics.retries++;
            try {
                // 재시도 시 사용자에게 진행 상황 알림
                if (attempt > 0) {
                    const backoffMs = transientRule.backoffBaseMs * Math.pow(2, attempt - 1);
                    logInfo(`[AgentEngine] [RETRY] ${agentName} 재시도 ${attempt}/${transientRule.maxRetries} (${backoffMs}ms 후)`);
                    onProgress(state.stage, `${agentName} 재시도 중... (${attempt}/${transientRule.maxRetries})`);
                    await new Promise(r => setTimeout(r, backoffMs));
                    this.checkAbort(signal);
                }

                const startTime = Date.now();
                
                // [Astra v4.0] 맥락 증폭 (Context Amplification)
                // 에이전트 실행 직전, 지식 신뢰도 및 충돌 처리 정책을 주입합니다.
                const amplifiedContext = this.amplifyContext(context, options);
                
                const result = await agent.execute(input, amplifiedContext, signal, options);
                const durationMs = Date.now() - startTime;
                
                // [Reliability Check] 충돌 위험도 추적
                const validation = AgentDataValidator.validateHandoff(agentName, result);
                state.resilienceMetrics.maxConflictScore = Math.max(state.resilienceMetrics.maxConflictScore, validation.conflictRisk);
                
                PerformanceProfiler.logLLMLatency(agentName, durationMs, result.length);
                
                return result;
            } catch (error: any) {
                lastError = error;
                const { type, rule } = ErrorClassifier.classify(error);

                switch (type) {
                    case ErrorType.ABORT:
                        // 사용자 취소 → 재시도 없이 즉시 전파
                        logInfo(`[AgentEngine] [ABORT] ${agentName} 실행 취소됨.`);
                        throw error;

                    case ErrorType.PERMANENT:
                        // 영구 오류 → 재시도 없이 즉시 중단, 사용자 메시지 첨부
                        logError(`[AgentEngine] [PERMANENT] ${agentName} 복구 불가: ${rule.userMessage}`);
                        
                        // [Self-Correction] 에러 발생 직전의 데이터 상태를 짧게 진단 (안전한 audit 모드 사용)
                        const auditResult = AgentDataValidator.audit(agentName, input.substring(0, 500));
                        logInfo(`[AgentEngine] [Pre-Failure Audit] Risk: ${auditResult.conflictRisk} | Issues: ${auditResult.issues.join(', ') || 'None'}`);

                        const enrichedError = new Error(`[${agentName}] ${rule.userMessage} (원인: ${error.message})`);
                        (enrichedError as any).originalError = error;
                        (enrichedError as any).errorType = ErrorType.PERMANENT;
                        throw enrichedError;

                    case ErrorType.TRANSIENT:
                        // 일시적 오류 → 재시도 가능 여부 확인
                        if (attempt >= transientRule.maxRetries) {
                            // [Intelligent Resilience] 재시도 실패 시 대체 경로(Fallback) 시도
                            if (transientRule.action === 'fallback' || options?.config?.allowFallback) {
                                logInfo(`[AgentEngine] [FALLBACK] ${agentName} 재시도 소진. 대체 데이터(Cache/Stale) 경로를 가동합니다.`);
                                state.resilienceMetrics.fallbacks++;
                                
                                // 1. 캐시 시도 (현재 프롬프트/컨텍스트 및 모델에 종속됨)
                                const currentModel = (options?.config?.model as string) || 'unknown';
                                const cached = CacheManager.get(input, context, currentModel);
                                if (cached) return cached;
                                
                                if (options?.priorResults?.['previousValidData']) {
                                    return options.priorResults['previousValidData'];
                                }
                            }

                            logError(`[AgentEngine] [TRANSIENT] ${agentName} 최대 재시도 횟수(${transientRule.maxRetries}) 소진.`);
                            const exhaustedError = new Error(
                                `[${agentName}] 일시적 연결 오류가 지속됩니다. ` +
                                `${transientRule.maxRetries}회 재시도 후에도 복구되지 않았습니다. ` +
                                `네트워크 연결 및 모델 서버 상태를 확인해 주세요. (원인: ${error.message})`
                            );
                            (exhaustedError as any).originalError = error;
                            (exhaustedError as any).errorType = ErrorType.TRANSIENT;
                            throw exhaustedError;
                        }
                        logInfo(`[AgentEngine] [TRANSIENT] ${agentName}에서 일시적 오류 감지: ${error.message}`);
                        break; // continue to next attempt
                }
            }
        }

        // 이론적으로 도달 불가하지만 안전장치
        throw lastError;
    }

    // ─── Private Helpers ───

    /**
     * MissionState를 통한 상태 전환 + 외부 콜백 호출.
     */
    private transition(state: MissionState, stage: PipelineStage, message: string, onProgress: (stage: PipelineStage, message: string) => void) {
        state.transition(stage, message);
        onProgress(stage, message);
    }

    /**
     * AbortSignal 확인을 일관되게 처리합니다.
     */
    private checkAbort(signal: AbortSignal): void {
        if (signal.aborted) {
            throw new Error('AbortError');
        }
    }

    /**
     * Writer가 사용할 초기 컨텍스트를 사전에 구성합니다.
     * Researcher와 병렬로 실행되어 Phase 3 진입 시 즉시 활용 가능합니다.
     */
    private async prepareWriterContext(prompt: string, plan: string, brainContext: string): Promise<string> {
        const contextSummary = [
            `[Original Prompt] ${prompt.substring(0, 200)}`,
            `[Plan Summary] ${plan.substring(0, 300)}`,
            `[Brain Context Available] ${brainContext ? 'Yes' : 'No'} (${brainContext?.length || 0} chars)`
        ].join('\n');

        logInfo(`[AgentEngine] [WriterPrep] 초기 컨텍스트 준비 완료 (${contextSummary.length} chars)`);
        return contextSummary;
    }

    private summarizeLog(data: string | undefined, length: number = 100): string {
        if (!data) return 'empty';
        const clean = data.replace(/\n/g, ' ').trim();
        return clean.length > length ? clean.substring(0, length) + '...' : clean;
    }

    private validateResult(data: string, step: string): number {
        // Error Recovery Matrix: Permanent 오류 발생을 방지하기 위한 선제적 핸드오프 검증
        const validation = AgentDataValidator.validateHandoff(step, data);
        return validation.score;
    }

    /**
     * [Astra v4.0] 맥락 증폭 로직
     * 지식 관리 정책 v4.0을 LLM 지시사항으로 변환하여 주입합니다.
     */
    private amplifyContext(context: string, options?: AgentExecuteOptions): string {
        const level = options?.abstractionLevel || 'balanced';
        
        const levelDirectives: Record<AbstractionLevel, string[]> = {
            'laser-focused': [
                "- [INTENSITY: HIGH] 불필요한 배경 설명과 중간 과정을 생략하고, 즉각적인 결론과 실행 가능한 To-Do 위주로 압축하십시오.",
                "- [QUALITY] 정보의 양보다 '추론 기여 밀도'를 극한으로 높여 핵심 위주로 서술하십시오."
            ],
            'balanced': [
                "- [INTENSITY: MEDIUM] 핵심 논리를 중심으로 설명하되, 판단 근거가 되는 주요 데이터는 포함하십시오.",
                "- [QUALITY] 지식의 양보다 '추론 기여 밀도'를 중시하여 서술하십시오."
            ],
            'comprehensive': [
                "- [INTENSITY: LOW] 전체 맥락을 파악할 수 있도록 배경 지식과 세부 데이터를 충분히 포함하십시오.",
                "- [QUALITY] 포괄적인 분석을 위해 가용한 모든 데이터를 구조화하여 제공하십시오."
            ]
        };

        const policyDirectives = [
            "\n### 🏛️ Knowledge Management Policy v4.1 (Filtering Applied)",
            `- [ABSTRACTION LEVEL] 현재 에이전트 간 인터페이스 정책은 '${level}' 모드입니다.`,
            ...levelDirectives[level],
            "- [CREDIBILITY] 정보 출처가 의도적으로 작성된 글인 경우 Medium 이상의 신뢰도를 부여하고 우선적으로 인용하십시오.",
            "- [CONFLICT] 상충되는 지식 발견 시 스스로 판단하지 말고 반드시 [CONFLICT WARNING] 플래그와 함께 두 관점을 모두 보고하십시오."
        ].join('\n');

        return `${context}\n${policyDirectives}`;
    }

    /**
     * [Astra v4.0] 선제적 제안 생성
     * 수행된 작업 결과를 분석하여 다음 단계의 의사결정 포크를 제안합니다.
     */
    private async generateProactiveAdvice(report: string, originalPrompt: string, context: string, signal: AbortSignal): Promise<string> {
        // [Structural Fix] 절단 없는 컨텍스트 전달 (LLM 상상력 제한)
        const advicePrompt = `사용자의 원래 요청과 작성된 최종 리포트를 바탕으로, 
사용자가 다음에 내려야 할 '전략적 의사결정'이나 '실행 작업' 3가지를 구체적으로 제안해주십시오. 
존재하지 않는 사실을 지어내지 말고, 리포트에 명시된 근거만을 활용하십시오.

원래 요청: ${originalPrompt}
리포트 내용: 
${report}`;

        try {
            // Advisor 전용 설정을 주입하여 역할 혼용 방지
            return await this.writer.execute(advicePrompt, context, signal, { 
                config: { 
                    role: 'advisor',
                    temperature: 0.1, // 창의성 억제, 사실성 강화
                    maxTokens: 500
                } 
            });
        } catch (err) {
            return "다음 단계에 대한 자동 제안을 생성하지 못했습니다. 리포트의 결론 섹션을 참고해 주세요.";
        }
    }
}
