import fs from 'fs';
import path from 'path';
import { EventEmitter } from 'events';
import { getErrorMessage } from '../types/index.js';
/**
 * Checkpoint Manager for saving and restoring file states
 */
export class CheckpointManager extends EventEmitter {
    checkpoints = [];
    maxCheckpoints;
    autoCheckpoint;
    workingDirectory;
    constructor(options = {}) {
        super();
        this.maxCheckpoints = options.maxCheckpoints || 50;
        this.autoCheckpoint = options.autoCheckpoint ?? true;
        this.workingDirectory = process.cwd();
    }
    /**
     * Create a new checkpoint
     */
    createCheckpoint(description, files) {
        const checkpoint = {
            id: this.generateId(),
            timestamp: new Date(),
            description,
            files: [],
            workingDirectory: this.workingDirectory
        };
        if (files && files.length > 0) {
            checkpoint.files = this.snapshotFiles(files);
        }
        this.checkpoints.push(checkpoint);
        // Trim old checkpoints if exceeding max
        while (this.checkpoints.length > this.maxCheckpoints) {
            this.checkpoints.shift();
        }
        this.emit('checkpoint-created', checkpoint);
        return checkpoint;
    }
    /**
     * Create a checkpoint before modifying a file
     */
    checkpointBeforeEdit(filePath, description) {
        const resolvedPath = path.resolve(this.workingDirectory, filePath);
        const desc = description || `Before editing: ${path.basename(filePath)}`;
        const checkpoint = this.createCheckpoint(desc, [resolvedPath]);
        return checkpoint;
    }
    /**
     * Create a checkpoint before creating a file
     */
    checkpointBeforeCreate(filePath, description) {
        const resolvedPath = path.resolve(this.workingDirectory, filePath);
        const desc = description || `Before creating: ${path.basename(filePath)}`;
        // Snapshot the file (will mark it as non-existent if it doesn't exist)
        const checkpoint = this.createCheckpoint(desc, [resolvedPath]);
        return checkpoint;
    }
    /**
     * Snapshot multiple files
     */
    snapshotFiles(filePaths) {
        const snapshots = [];
        for (const filePath of filePaths) {
            try {
                const resolvedPath = path.resolve(this.workingDirectory, filePath);
                if (fs.existsSync(resolvedPath)) {
                    const stat = fs.statSync(resolvedPath);
                    if (stat.isFile()) {
                        const content = fs.readFileSync(resolvedPath, 'utf-8');
                        snapshots.push({
                            path: resolvedPath,
                            content,
                            existed: true
                        });
                    }
                }
                else {
                    // File doesn't exist yet
                    snapshots.push({
                        path: resolvedPath,
                        content: '',
                        existed: false
                    });
                }
            }
            catch (_error) {
                // Skip files that can't be read
            }
        }
        return snapshots;
    }
    /**
     * Rewind to a specific checkpoint
     */
    rewindTo(checkpointId) {
        const checkpoint = this.checkpoints.find(cp => cp.id === checkpointId);
        if (!checkpoint) {
            return {
                success: false,
                restored: [],
                errors: [`Checkpoint not found: ${checkpointId}`]
            };
        }
        const restored = [];
        const errors = [];
        for (const snapshot of checkpoint.files) {
            try {
                if (snapshot.existed) {
                    // Restore file content
                    const dir = path.dirname(snapshot.path);
                    if (!fs.existsSync(dir)) {
                        fs.mkdirSync(dir, { recursive: true });
                    }
                    fs.writeFileSync(snapshot.path, snapshot.content);
                    restored.push(snapshot.path);
                }
                else {
                    // File didn't exist, delete it if it exists now
                    if (fs.existsSync(snapshot.path)) {
                        fs.unlinkSync(snapshot.path);
                        restored.push(`Deleted: ${snapshot.path}`);
                    }
                }
            }
            catch (error) {
                errors.push(`Failed to restore ${snapshot.path}: ${getErrorMessage(error)}`);
            }
        }
        // Remove checkpoints created after this one
        const checkpointIndex = this.checkpoints.indexOf(checkpoint);
        if (checkpointIndex >= 0) {
            this.checkpoints = this.checkpoints.slice(0, checkpointIndex + 1);
        }
        this.emit('rewind', checkpoint, restored, errors);
        return {
            success: errors.length === 0,
            restored,
            errors
        };
    }
    /**
     * Rewind to the last checkpoint
     */
    rewindToLast() {
        if (this.checkpoints.length === 0) {
            return {
                success: false,
                restored: [],
                errors: ['No checkpoints available']
            };
        }
        const lastCheckpoint = this.checkpoints[this.checkpoints.length - 1];
        const result = this.rewindTo(lastCheckpoint.id);
        return {
            ...result,
            checkpoint: lastCheckpoint
        };
    }
    /**
     * Get all checkpoints
     */
    getCheckpoints() {
        return [...this.checkpoints];
    }
    /**
     * Get a specific checkpoint by ID
     */
    getCheckpoint(id) {
        return this.checkpoints.find(cp => cp.id === id);
    }
    /**
     * Get the last N checkpoints
     */
    getRecentCheckpoints(count = 10) {
        return this.checkpoints.slice(-count);
    }
    /**
     * Clear all checkpoints
     */
    clearCheckpoints() {
        this.checkpoints = [];
        this.emit('checkpoints-cleared');
    }
    /**
     * Delete a specific checkpoint
     */
    deleteCheckpoint(id) {
        const index = this.checkpoints.findIndex(cp => cp.id === id);
        if (index >= 0) {
            this.checkpoints.splice(index, 1);
            return true;
        }
        return false;
    }
    /**
     * Check if auto-checkpoint is enabled
     */
    isAutoCheckpointEnabled() {
        return this.autoCheckpoint;
    }
    /**
     * Enable or disable auto-checkpoint
     */
    setAutoCheckpoint(enabled) {
        this.autoCheckpoint = enabled;
    }
    /**
     * Format checkpoint for display
     */
    formatCheckpoint(checkpoint) {
        const time = checkpoint.timestamp.toLocaleTimeString();
        const filesCount = checkpoint.files.length;
        return `[${checkpoint.id.slice(0, 8)}] ${time} - ${checkpoint.description} (${filesCount} file${filesCount !== 1 ? 's' : ''})`;
    }
    /**
     * Format all checkpoints for display
     */
    formatCheckpointList() {
        if (this.checkpoints.length === 0) {
            return 'No checkpoints available.';
        }
        const header = 'Checkpoints:\n' + '─'.repeat(50) + '\n';
        const list = this.checkpoints
            .map((cp, index) => `${index + 1}. ${this.formatCheckpoint(cp)}`)
            .join('\n');
        return header + list;
    }
    /**
     * Generate a unique checkpoint ID
     */
    generateId() {
        const timestamp = Date.now().toString(36);
        const random = Math.random().toString(36).substring(2, 8);
        return `cp_${timestamp}_${random}`;
    }
    /**
     * Get statistics about checkpoints
     */
    getStats() {
        const totalFiles = this.checkpoints.reduce((sum, cp) => sum + cp.files.length, 0);
        return {
            count: this.checkpoints.length,
            totalFiles,
            oldestTimestamp: this.checkpoints[0]?.timestamp,
            newestTimestamp: this.checkpoints[this.checkpoints.length - 1]?.timestamp
        };
    }
    /**
     * Dispose and cleanup resources
     */
    dispose() {
        this.checkpoints = [];
        this.removeAllListeners();
    }
}
// Singleton instance
let checkpointManagerInstance = null;
export function getCheckpointManager(options) {
    if (!checkpointManagerInstance) {
        checkpointManagerInstance = new CheckpointManager(options);
    }
    return checkpointManagerInstance;
}
export function resetCheckpointManager() {
    if (checkpointManagerInstance) {
        checkpointManagerInstance.dispose();
    }
    checkpointManagerInstance = null;
}
//# sourceMappingURL=checkpoint-manager.js.map