"use strict";
/**
 * Generation Orchestrator
 * Coordinates code generation with checkpoint management, error handling, and retry logic
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.GenerationOrchestrator = void 0;
const code_generator_1 = require("./code-generator");
const checkpoint_manager_1 = require("../utils/checkpoint-manager");
const error_handler_1 = require("../utils/error-handler");
const retry_manager_1 = require("../utils/retry-manager");
const workflow_engine_1 = require("../engine/workflow-engine");
class GenerationOrchestrator {
    codeGenerator;
    checkpointManager;
    errorAggregator;
    workflowEngine;
    constructor() {
        this.codeGenerator = new code_generator_1.CodeGenerator();
        this.errorAggregator = new error_handler_1.ErrorAggregator();
        this.workflowEngine = new workflow_engine_1.WorkflowEngine();
    }
    /**
     * Orchestrate code generation with full error handling and checkpointing
     */
    async generate(workflow, options) {
        // Initialize checkpoint manager unless disabled
        if (!options.noCheckpoint) {
            this.checkpointManager = new checkpoint_manager_1.CheckpointManager(options.outputDirectory);
            this.checkpointManager.initialize();
        }
        // Check if can resume from previous failure
        if (options.resume && this.checkpointManager?.canResume()) {
            return this.resumeGeneration(workflow, options);
        }
        // Execute generation with error handling
        try {
            return await this.executeGeneration(workflow, options);
        }
        catch (error) {
            return this.handleGenerationFailure(error, options);
        }
    }
    /**
     * Execute the full generation process
     */
    async executeGeneration(workflow, options) {
        const result = {
            files: [],
            written: [],
            skipped: [],
            errors: [],
            warnings: [],
            retries: 0,
        };
        try {
            // Stage 1: Validation
            await this.executeStage(checkpoint_manager_1.GenerationStage.VALIDATION, async () => {
                const validation = await this.validateWorkflow(workflow);
                if (!validation.valid) {
                    validation.errors.forEach(err => this.errorAggregator.add(error_handler_1.ErrorFactory.invalidWorkflowStructure(err)));
                    throw new Error(`Workflow validation failed: ${validation.errors.join(', ')}`);
                }
                result.warnings.push(...validation.warnings);
            });
            // Stage 2: Analysis
            await this.executeStage(checkpoint_manager_1.GenerationStage.ANALYSIS, async () => {
                const _executionPlan = this.workflowEngine.analyze(workflow);
                // The analyze method will throw an error if there are issues
                // such as circular dependencies or invalid references
                // No need to check explicitly here
            });
            // Stage 3: Infrastructure
            await this.executeStage(checkpoint_manager_1.GenerationStage.INFRASTRUCTURE, async () => {
                // Infrastructure generation happens within CodeGenerator
                // Just track the checkpoint here
            });
            // Stage 4: Component Generation
            await this.executeStage(checkpoint_manager_1.GenerationStage.COMPONENT_GENERATION, async () => {
                const componentNames = Object.keys(workflow.stack);
                const succeededComponents = [];
                const failedComponents = [];
                const componentErrors = [];
                for (const componentName of componentNames) {
                    try {
                        // Create checkpoint per component
                        if (this.checkpointManager) {
                            this.checkpointManager.createCheckpoint(checkpoint_manager_1.GenerationStage.COMPONENT_GENERATION, componentName);
                        }
                        // Generate component (handled by CodeGenerator)
                        // We'll track success/failure here
                        succeededComponents.push(componentName);
                    }
                    catch (error) {
                        failedComponents.push(componentName);
                        componentErrors.push({
                            component: componentName,
                            error: error instanceof Error ? error.message : String(error),
                        });
                        // Don't throw immediately - collect all errors
                    }
                }
                // If some components failed, create partial generation error
                if (failedComponents.length > 0) {
                    const partialError = error_handler_1.ErrorFactory.partialGeneration(succeededComponents, failedComponents, componentErrors);
                    // Check if can recover automatically
                    if (partialError.isRecoverable()) {
                        result.warnings.push(`Partial generation: ${failedComponents.length} components failed`);
                    }
                    else {
                        throw partialError;
                    }
                }
            });
            // Stage 5: Configuration
            await this.executeStage(checkpoint_manager_1.GenerationStage.CONFIGURATION, async () => {
                // Docker, CI/CD, etc. generation
                // Handled by CodeGenerator
            });
            // Stage 6: Finalization
            await this.executeStage(checkpoint_manager_1.GenerationStage.FINALIZATION, async () => {
                // Manifest generation
                // Handled by CodeGenerator
            });
            // Execute actual code generation with retry logic
            const genResult = await this.executeWithRetry(() => this.codeGenerator.generate(workflow, options), options);
            // Merge results
            result.files = genResult.files;
            result.written = genResult.written;
            result.skipped = genResult.skipped;
            result.errors = genResult.errors;
            result.warnings.push(...genResult.warnings);
            // Track generated files in checkpoint
            if (this.checkpointManager) {
                for (const file of genResult.written) {
                    this.checkpointManager.recordFileCreated(file);
                }
            }
            // Stage 7: Complete
            if (this.checkpointManager) {
                this.checkpointManager.createCheckpoint(checkpoint_manager_1.GenerationStage.COMPLETE);
            }
            // Add checkpoint info to result
            if (this.checkpointManager) {
                const progress = this.checkpointManager.getProgress();
                result.checkpoint = {
                    stage: progress.stage,
                    percentage: progress.percentage,
                    canResume: this.checkpointManager.canResume(),
                };
                // Clean up checkpoints after successful generation
                if (!options.dryRun) {
                    this.checkpointManager.cleanup();
                }
            }
            return result;
        }
        catch (error) {
            // Handle generation failure
            if (error instanceof error_handler_1.EnhancedError) {
                result.errors.push(error.format());
            }
            else {
                result.errors.push(error instanceof Error ? error.message : String(error));
            }
            // Auto-rollback if enabled
            if (options.autoRollback !== false && this.checkpointManager) {
                const rollbackResult = this.checkpointManager.rollback();
                if (rollbackResult.success) {
                    result.rolledBack = true;
                    result.warnings.push(`Rolled back to last checkpoint: ${rollbackResult.filesRemoved?.length || 0} files removed`);
                }
            }
            throw error;
        }
    }
    /**
     * Execute a generation stage with checkpoint tracking
     */
    async executeStage(stage, action) {
        // Create checkpoint
        if (this.checkpointManager) {
            this.checkpointManager.createCheckpoint(stage);
        }
        // Execute stage
        try {
            await action();
        }
        catch (error) {
            // Enhance error with stage context
            if (error instanceof Error) {
                error.message = `[${stage}] ${error.message}`;
            }
            throw error;
        }
    }
    /**
     * Execute generation with retry logic for transient failures
     */
    async executeWithRetry(action, options) {
        if (options.retryTransient === false) {
            return action();
        }
        const result = await retry_manager_1.RetryManager.execute(action, {
            maxAttempts: options.maxRetries || 3,
            strategy: retry_manager_1.RetryStrategy.EXPONENTIAL_BACKOFF,
            initialDelay: 1000,
            maxDelay: 10000,
            onRetry: (attempt, error) => {
                console.log(`  Retrying generation (attempt ${attempt}): ${error.message}`);
            },
            shouldRetry: (error) => {
                // Don't retry validation or permanent errors
                if (error.message.includes('validation'))
                    return false;
                if (error.message.includes('invalid'))
                    return false;
                return true;
            },
        });
        if (!result.success) {
            throw result.error || new Error('Generation failed after retries');
        }
        return result.result;
    }
    /**
     * Validate workflow before generation
     */
    async validateWorkflow(workflow) {
        return retry_manager_1.RetryHelpers.retryFileOperation(async () => this.workflowEngine.validate(workflow), 'validate workflow');
    }
    /**
     * Resume generation from last checkpoint
     */
    async resumeGeneration(workflow, options) {
        if (!this.checkpointManager) {
            throw new Error('Cannot resume: checkpoint manager not initialized');
        }
        const resumePoint = this.checkpointManager.getResumePoint();
        if (!resumePoint) {
            throw new Error('Cannot resume: no valid resume point found');
        }
        console.log(`\n📊 Resuming from checkpoint: ${resumePoint.stage}`);
        if (resumePoint.component) {
            console.log(`   Component: ${resumePoint.component}`);
        }
        // Show progress
        const progress = this.checkpointManager.getProgress();
        console.log(`   Progress: ${progress.percentage}%`);
        console.log(`   Completed: ${progress.completedStages.join(', ')}\n`);
        // Continue generation from resume point
        // For now, we'll restart the full generation
        // In a more advanced implementation, we'd skip completed stages
        return this.executeGeneration(workflow, {
            ...options,
            resume: false, // Prevent infinite recursion
        });
    }
    /**
     * Handle generation failure
     */
    handleGenerationFailure(error, _options) {
        const result = {
            files: [],
            written: [],
            skipped: [],
            errors: [],
            warnings: [],
        };
        // Convert error to EnhancedError if needed
        let enhancedError;
        if (error instanceof error_handler_1.EnhancedError) {
            enhancedError = error;
        }
        else if (error instanceof Error) {
            enhancedError = new error_handler_1.EnhancedError({
                code: error_handler_1.ErrorCode.GENERATOR_FAILED,
                severity: error_handler_1.ErrorSeverity.ERROR,
                message: error.message,
                details: error.stack,
            });
        }
        else {
            enhancedError = new error_handler_1.EnhancedError({
                code: error_handler_1.ErrorCode.GENERATOR_FAILED,
                severity: error_handler_1.ErrorSeverity.ERROR,
                message: String(error),
            });
        }
        result.errors.push(enhancedError.format());
        // Show checkpoint summary if available
        if (this.checkpointManager) {
            const summary = this.checkpointManager.getSummary();
            result.warnings.push(summary);
            // Add checkpoint info
            const progress = this.checkpointManager.getProgress();
            result.checkpoint = {
                stage: progress.stage,
                percentage: progress.percentage,
                canResume: this.checkpointManager.canResume(),
            };
        }
        return result;
    }
    /**
     * Get checkpoint manager (for testing)
     */
    getCheckpointManager() {
        return this.checkpointManager;
    }
    /**
     * Get error aggregator (for testing)
     */
    getErrorAggregator() {
        return this.errorAggregator;
    }
}
exports.GenerationOrchestrator = GenerationOrchestrator;
//# sourceMappingURL=generation-orchestrator.js.map