/**
 * Self-Healing
 *
 * Recognizes error patterns and applies automatic fix strategies.
 * Escalates after max attempts.
 */
import { EventEmitter } from 'events';
import { logger } from '../../utils/logger.js';
// ============================================================================
// Built-in Error Patterns
// ============================================================================
const BUILTIN_PATTERNS = [
    {
        name: 'FileNotFound',
        pattern: /ENOENT|no such file or directory|file not found/i,
        strategy: 'retry',
        priority: 10,
    },
    {
        name: 'PermissionDenied',
        pattern: /EACCES|permission denied|access denied/i,
        strategy: 'change_permissions',
        priority: 20,
    },
    {
        name: 'SyntaxError',
        pattern: /SyntaxError|unexpected token|parse error/i,
        strategy: 'fix_syntax',
        priority: 15,
    },
    {
        name: 'ModuleNotFound',
        pattern: /Cannot find module|MODULE_NOT_FOUND|not found.*module/i,
        strategy: 'install_dependency',
        priority: 25,
    },
    {
        name: 'NetworkError',
        pattern: /ECONNREFUSED|ETIMEDOUT|network error|fetch failed/i,
        strategy: 'retry_with_backoff',
        priority: 5,
    },
    {
        name: 'OutOfMemory',
        pattern: /ENOMEM|out of memory|heap out of memory/i,
        strategy: 'escalate',
        priority: 30,
    },
];
// ============================================================================
// Self-Healing Engine
// ============================================================================
export class SelfHealing extends EventEmitter {
    patterns;
    customStrategies = new Map();
    constructor() {
        super();
        this.patterns = [...BUILTIN_PATTERNS];
    }
    /**
     * Add a custom error pattern
     */
    addPattern(pattern) {
        this.patterns.push(pattern);
        this.patterns.sort((a, b) => b.priority - a.priority);
    }
    /**
     * Register a custom healing strategy
     */
    registerStrategy(name, handler) {
        this.customStrategies.set(name, handler);
    }
    /**
     * Attempt to heal an error
     */
    async attemptHeal(error, context, maxAttempts = 3, retryAction) {
        const message = error.message || String(error);
        let attempts = 0;
        // Match error to pattern
        const matched = this.patterns.find(p => p.pattern.test(message));
        if (!matched) {
            return { healed: false, strategy: 'escalate', attempts: 0, error: 'No matching pattern' };
        }
        this.emit('healing:start', { pattern: matched.name, strategy: matched.strategy });
        while (attempts < maxAttempts) {
            attempts++;
            try {
                let healed = false;
                switch (matched.strategy) {
                    case 'retry':
                        if (retryAction) {
                            await retryAction();
                            healed = true;
                        }
                        break;
                    case 'retry_with_backoff':
                        if (retryAction) {
                            await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempts - 1)));
                            await retryAction();
                            healed = true;
                        }
                        break;
                    case 'custom': {
                        const handler = this.customStrategies.get(matched.name);
                        if (handler) {
                            healed = await handler(error, context);
                        }
                        break;
                    }
                    case 'escalate':
                        this.emit('healing:escalate', { pattern: matched.name, error: message, attempts });
                        return { healed: false, strategy: 'escalate', attempts, error: 'Escalated' };
                    default:
                        // For strategies that need external implementation
                        this.emit('healing:needs-action', { strategy: matched.strategy, context });
                        return { healed: false, strategy: matched.strategy, attempts, fixApplied: matched.strategy };
                }
                if (healed) {
                    this.emit('healing:success', { pattern: matched.name, attempts });
                    return { healed: true, strategy: matched.strategy, attempts };
                }
            }
            catch (retryError) {
                logger.debug(`Healing attempt ${attempts} failed`, { error: String(retryError) });
            }
        }
        this.emit('healing:failed', { pattern: matched.name, attempts });
        return { healed: false, strategy: matched.strategy, attempts, error: 'Max attempts reached' };
    }
    /**
     * Match an error to a pattern (without healing)
     */
    matchPattern(error) {
        const message = error.message || String(error);
        return this.patterns.find(p => p.pattern.test(message)) || null;
    }
    /**
     * Get all registered patterns
     */
    getPatterns() {
        return [...this.patterns];
    }
}
// ============================================================================
// Singleton
// ============================================================================
let healingInstance = null;
export function getSelfHealing() {
    if (!healingInstance) {
        healingInstance = new SelfHealing();
    }
    return healingInstance;
}
export function resetSelfHealing() {
    healingInstance = null;
}
//# sourceMappingURL=self-healing.js.map