"use strict";
/**
 * Checkpoint Manager for Generation Process
 * Enables rollback and recovery from partial failures
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CheckpointManager = exports.GenerationStage = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const crypto = __importStar(require("crypto"));
var GenerationStage;
(function (GenerationStage) {
    GenerationStage["VALIDATION"] = "validation";
    GenerationStage["ANALYSIS"] = "analysis";
    GenerationStage["INFRASTRUCTURE"] = "infrastructure";
    GenerationStage["COMPONENT_GENERATION"] = "component_generation";
    GenerationStage["CONFIGURATION"] = "configuration";
    GenerationStage["FINALIZATION"] = "finalization";
    GenerationStage["COMPLETE"] = "complete";
})(GenerationStage || (exports.GenerationStage = GenerationStage = {}));
class CheckpointManager {
    outputDir;
    checkpoints = [];
    checkpointDir;
    currentCheckpoint;
    constructor(outputDir) {
        this.outputDir = outputDir;
        this.checkpointDir = path.join(outputDir, '.bangstack', 'checkpoints');
    }
    /**
     * Initialize checkpoint system
     */
    initialize() {
        if (!fs.existsSync(this.checkpointDir)) {
            fs.mkdirSync(this.checkpointDir, { recursive: true });
        }
        // Load existing checkpoints
        this.loadCheckpoints();
    }
    /**
     * Create a new checkpoint
     */
    createCheckpoint(stage, component, metadata) {
        const id = this.generateCheckpointId();
        const checkpoint = {
            id,
            timestamp: new Date().toISOString(),
            stage,
            component,
            filesCreated: [],
            filesModified: [],
            directoriesCreated: [],
            metadata: metadata || {},
        };
        this.checkpoints.push(checkpoint);
        this.currentCheckpoint = checkpoint;
        this.saveCheckpoint(checkpoint);
        return id;
    }
    /**
     * Record file creation
     */
    recordFileCreated(filePath) {
        if (this.currentCheckpoint) {
            this.currentCheckpoint.filesCreated.push(filePath);
            this.saveCheckpoint(this.currentCheckpoint);
        }
    }
    /**
     * Record file modification with backup
     */
    recordFileModified(filePath) {
        if (this.currentCheckpoint && fs.existsSync(filePath)) {
            const backupPath = this.createBackup(filePath);
            this.currentCheckpoint.filesModified.push({ path: filePath, backup: backupPath });
            this.saveCheckpoint(this.currentCheckpoint);
        }
    }
    /**
     * Record directory creation
     */
    recordDirectoryCreated(dirPath) {
        if (this.currentCheckpoint) {
            this.currentCheckpoint.directoriesCreated.push(dirPath);
            this.saveCheckpoint(this.currentCheckpoint);
        }
    }
    /**
     * Rollback to a specific checkpoint
     */
    rollback(checkpointId) {
        const checkpoint = checkpointId
            ? this.checkpoints.find(c => c.id === checkpointId)
            : this.getLastSuccessfulCheckpoint();
        if (!checkpoint) {
            return {
                success: false,
                message: 'No checkpoint found to rollback to',
            };
        }
        const result = {
            success: true,
            message: `Rolling back to checkpoint: ${checkpoint.stage}`,
            filesRemoved: [],
            filesRestored: [],
            directoriesRemoved: [],
        };
        try {
            // Get all checkpoints after the target
            const checkpointsToRollback = this.checkpoints.filter(c => new Date(c.timestamp) > new Date(checkpoint.timestamp));
            // Rollback in reverse order
            for (const cp of checkpointsToRollback.reverse()) {
                // Remove created files
                for (const filePath of cp.filesCreated) {
                    if (fs.existsSync(filePath)) {
                        fs.unlinkSync(filePath);
                        result.filesRemoved.push(filePath);
                    }
                }
                // Restore modified files from backup
                for (const { path: filePath, backup } of cp.filesModified) {
                    if (fs.existsSync(backup)) {
                        fs.copyFileSync(backup, filePath);
                        fs.unlinkSync(backup);
                        result.filesRestored.push(filePath);
                    }
                }
                // Remove created directories (if empty)
                for (const dirPath of cp.directoriesCreated) {
                    if (fs.existsSync(dirPath) && this.isDirectoryEmpty(dirPath)) {
                        fs.rmdirSync(dirPath);
                        result.directoriesRemoved.push(dirPath);
                    }
                }
                // Remove checkpoint file
                this.removeCheckpoint(cp.id);
            }
            return result;
        }
        catch (error) {
            return {
                success: false,
                message: `Rollback failed: ${error instanceof Error ? error.message : String(error)}`,
            };
        }
    }
    /**
     * Get generation progress
     */
    getProgress() {
        if (this.checkpoints.length === 0) {
            return {
                stage: GenerationStage.VALIDATION,
                percentage: 0,
                completedStages: [],
            };
        }
        const lastCheckpoint = this.checkpoints[this.checkpoints.length - 1];
        const allStages = Object.values(GenerationStage);
        const currentStageIndex = allStages.indexOf(lastCheckpoint.stage);
        // Add 1 to index to show that we've completed the current stage
        const percentage = Math.round(((currentStageIndex + 1) / allStages.length) * 100);
        return {
            stage: lastCheckpoint.stage,
            percentage,
            completedStages: this.checkpoints.map(c => c.stage),
            currentComponent: lastCheckpoint.component,
        };
    }
    /**
     * Get last successful checkpoint
     */
    getLastSuccessfulCheckpoint() {
        return this.checkpoints[this.checkpoints.length - 1];
    }
    /**
     * Check if can resume from checkpoint
     */
    canResume() {
        return this.checkpoints.length > 0 &&
            this.checkpoints[this.checkpoints.length - 1].stage !== GenerationStage.COMPLETE;
    }
    /**
     * Get resume point
     */
    getResumePoint() {
        if (!this.canResume()) {
            return null;
        }
        const lastCheckpoint = this.checkpoints[this.checkpoints.length - 1];
        return {
            stage: lastCheckpoint.stage,
            component: lastCheckpoint.component,
        };
    }
    /**
     * Clean up checkpoints after successful completion
     */
    cleanup() {
        // Keep the complete checkpoint for history
        const completeCheckpoint = this.checkpoints.find(c => c.stage === GenerationStage.COMPLETE);
        if (completeCheckpoint) {
            // Remove all other checkpoints
            for (const checkpoint of this.checkpoints) {
                if (checkpoint.id !== completeCheckpoint.id) {
                    this.removeCheckpoint(checkpoint.id);
                }
            }
            // Clean up backup files
            const backupDir = path.join(this.checkpointDir, 'backups');
            if (fs.existsSync(backupDir)) {
                fs.rmSync(backupDir, { recursive: true, force: true });
            }
        }
    }
    /**
     * Get checkpoint summary for user
     */
    getSummary() {
        if (this.checkpoints.length === 0) {
            return 'No checkpoints found';
        }
        const lines = [];
        lines.push('\n📊 Generation Progress:\n');
        const progress = this.getProgress();
        lines.push(`   Stage: ${progress.stage}`);
        lines.push(`   Progress: ${progress.percentage}%`);
        if (progress.currentComponent) {
            lines.push(`   Current: ${progress.currentComponent}`);
        }
        lines.push('\n   Checkpoints:');
        this.checkpoints.forEach((cp, _index) => {
            const icon = cp.stage === GenerationStage.COMPLETE ? '✓' : '○';
            lines.push(`     ${icon} ${cp.stage}${cp.component ? ` (${cp.component})` : ''}`);
        });
        if (this.canResume()) {
            lines.push('\n   💡 Can resume from last checkpoint');
            lines.push('      Run: bang generate <workflow> --resume');
        }
        return lines.join('\n');
    }
    // Private helper methods
    generateCheckpointId() {
        return `cp_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`;
    }
    saveCheckpoint(checkpoint) {
        const checkpointPath = path.join(this.checkpointDir, `${checkpoint.id}.json`);
        fs.writeFileSync(checkpointPath, JSON.stringify(checkpoint, null, 2));
    }
    loadCheckpoints() {
        if (!fs.existsSync(this.checkpointDir)) {
            return;
        }
        const files = fs.readdirSync(this.checkpointDir);
        this.checkpoints = files
            .filter(f => f.endsWith('.json'))
            .map(f => {
            const content = fs.readFileSync(path.join(this.checkpointDir, f), 'utf-8');
            return JSON.parse(content);
        })
            .sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
    }
    removeCheckpoint(checkpointId) {
        const checkpointPath = path.join(this.checkpointDir, `${checkpointId}.json`);
        if (fs.existsSync(checkpointPath)) {
            fs.unlinkSync(checkpointPath);
        }
        this.checkpoints = this.checkpoints.filter(c => c.id !== checkpointId);
    }
    createBackup(filePath) {
        const backupDir = path.join(this.checkpointDir, 'backups');
        if (!fs.existsSync(backupDir)) {
            fs.mkdirSync(backupDir, { recursive: true });
        }
        const timestamp = Date.now();
        const fileName = path.basename(filePath);
        const backupPath = path.join(backupDir, `${fileName}.${timestamp}.backup`);
        fs.copyFileSync(filePath, backupPath);
        return backupPath;
    }
    isDirectoryEmpty(dirPath) {
        const files = fs.readdirSync(dirPath);
        return files.length === 0;
    }
}
exports.CheckpointManager = CheckpointManager;
//# sourceMappingURL=checkpoint-manager.js.map