/**
 * Health Monitor
 *
 * Monitors daemon health: CPU/memory usage, auto-recovery, health endpoints.
 */
import { EventEmitter } from 'events';
import * as os from 'os';
import { logger } from '../utils/logger.js';
const DEFAULT_CONFIG = {
    intervalMs: 30000,
    memoryWarningThreshold: 80,
    memoryCriticalThreshold: 95,
    maxUnhealthyChecks: 3,
};
// ============================================================================
// Health Monitor
// ============================================================================
export class HealthMonitor extends EventEmitter {
    config;
    timer = null;
    running = false;
    startTime = 0;
    unhealthyCount = 0;
    lastMetrics = null;
    serviceChecks = new Map();
    constructor(config = {}) {
        super();
        this.config = { ...DEFAULT_CONFIG, ...config };
    }
    /**
     * Register a service health check
     */
    registerServiceCheck(name, check) {
        this.serviceChecks.set(name, check);
    }
    /**
     * Start monitoring
     */
    start() {
        if (this.running)
            return;
        this.startTime = Date.now();
        this.running = true;
        this.timer = setInterval(() => this.check(), this.config.intervalMs);
        logger.debug('Health monitor started');
    }
    /**
     * Stop monitoring
     */
    stop() {
        if (this.timer) {
            clearInterval(this.timer);
            this.timer = null;
        }
        this.running = false;
        logger.debug('Health monitor stopped');
    }
    /**
     * Run a health check
     */
    check() {
        const memUsage = process.memoryUsage();
        const totalMem = os.totalmem();
        const freeMem = os.freemem();
        const usedMem = totalMem - freeMem;
        const services = Array.from(this.serviceChecks.entries()).map(([name, check]) => ({
            name,
            healthy: check(),
        }));
        const metrics = {
            timestamp: new Date(),
            cpu: {
                usage: os.loadavg()[0] * 100 / os.cpus().length,
                loadAvg: os.loadavg(),
            },
            memory: {
                total: totalMem,
                used: usedMem,
                free: freeMem,
                heapUsed: memUsage.heapUsed,
                heapTotal: memUsage.heapTotal,
                rss: memUsage.rss,
                percentage: (usedMem / totalMem) * 100,
            },
            uptime: Date.now() - this.startTime,
            services,
        };
        this.lastMetrics = metrics;
        // Check thresholds — increment unhealthyCount at most once per check cycle
        let isUnhealthy = false;
        if (metrics.memory.percentage >= this.config.memoryCriticalThreshold) {
            this.emit('critical', { type: 'memory', metrics });
            isUnhealthy = true;
        }
        else if (metrics.memory.percentage >= this.config.memoryWarningThreshold) {
            this.emit('warning', { type: 'memory', metrics });
            isUnhealthy = true;
        }
        // Check for unhealthy services
        const unhealthyServices = services.filter(s => !s.healthy);
        if (unhealthyServices.length > 0) {
            this.emit('service:unhealthy', { services: unhealthyServices });
            isUnhealthy = true;
        }
        if (isUnhealthy) {
            this.unhealthyCount++;
        }
        else {
            this.unhealthyCount = 0;
        }
        // Auto-recovery trigger
        if (this.unhealthyCount >= this.config.maxUnhealthyChecks) {
            this.emit('recovery-needed', { metrics, unhealthyCount: this.unhealthyCount });
            this.unhealthyCount = 0;
        }
        this.emit('check', metrics);
        return metrics;
    }
    /**
     * Get last collected metrics
     */
    getLastMetrics() {
        return this.lastMetrics;
    }
    /**
     * Get health summary for API endpoint
     */
    getHealthSummary() {
        const metrics = this.lastMetrics || this.check();
        let status = 'healthy';
        if (metrics.memory.percentage >= this.config.memoryCriticalThreshold) {
            status = 'critical';
        }
        else if (metrics.memory.percentage >= this.config.memoryWarningThreshold) {
            status = 'warning';
        }
        return {
            status,
            uptime: metrics.uptime,
            memory: {
                percentage: Math.round(metrics.memory.percentage * 100) / 100,
                rss: metrics.memory.rss,
            },
            services: metrics.services,
        };
    }
    isRunning() {
        return this.running;
    }
}
// ============================================================================
// Singleton
// ============================================================================
let monitorInstance = null;
export function getHealthMonitor(config) {
    if (!monitorInstance) {
        monitorInstance = new HealthMonitor(config);
    }
    return monitorInstance;
}
export function resetHealthMonitor() {
    if (monitorInstance) {
        monitorInstance.stop();
    }
    monitorInstance = null;
}
//# sourceMappingURL=health-monitor.js.map