/**
 * Resource Monitor
 * Real-time resource tracking with cost calculation
 * Sealed namespace for immutability
 */
import { Env, Logger, NodeSingletons } from '../../../src/index.js';
const getOsModule = () => NodeSingletons?.os ?? null;
const safeTotalMemory = () => {
    const os = getOsModule();
    if (!os?.totalmem)
        return 0;
    try {
        return os.totalmem();
    }
    catch {
        return 0;
    }
};
const safeFreeMemory = () => {
    const os = getOsModule();
    if (!os?.freemem)
        return 0;
    try {
        return os.freemem();
    }
    catch {
        return 0;
    }
};
const safeLoadAverage = () => {
    const os = getOsModule();
    if (!os?.loadavg)
        return [0, 0, 0];
    try {
        return os.loadavg();
    }
    catch {
        return [0, 0, 0];
    }
};
const safeCpuCount = () => {
    const os = getOsModule();
    if (!os?.cpus)
        return 1;
    try {
        return Math.max(1, os.cpus().length);
    }
    catch {
        return 1;
    }
};
const safePlatform = () => {
    const os = getOsModule();
    if (!os?.platform)
        return 'unknown';
    try {
        return os.platform();
    }
    catch {
        return 'unknown';
    }
};
const safeArch = () => {
    const os = getOsModule();
    if (!os?.arch)
        return 'unknown';
    try {
        return os.arch();
    }
    catch {
        return 'unknown';
    }
};
const safeHostname = () => {
    const os = getOsModule();
    if (!os?.hostname)
        return 'unknown';
    try {
        return os.hostname();
    }
    catch {
        return 'unknown';
    }
};
const safeUptime = () => {
    const os = getOsModule();
    if (!os?.uptime)
        return 0;
    try {
        return os.uptime();
    }
    catch {
        return 0;
    }
};
const safeProcessCpuUsage = () => {
    if (!process?.cpuUsage)
        return { user: 0, system: 0 };
    try {
        return process.cpuUsage();
    }
    catch {
        return { user: 0, system: 0 };
    }
};
// Default cost configuration (AWS-like pricing)
const DEFAULT_COST_CONFIG = {
    computeCostPerCoreHour: 0.0416, // ~$0.0416 per vCPU hour (t3.medium equivalent)
    memoryCostPerGBHour: 0.0052, // ~$0.0052 per GB hour
    networkCostPerGB: 0.09, // $0.09 per GB transferred
    diskCostPerGB: 0.1, // $0.10 per GB/month
    spotInstanceDiscount: 70, // 70% discount for spot instances
};
// Internal state
let costConfig = { ...DEFAULT_COST_CONFIG };
let monitoringInterval = null;
const resourceHistory = new Map();
const alertHistory = new Map();
// Memory management constants
const MAX_HISTORY_SIZE = 1000; // Keep last 1000 snapshots per worker
const MAX_ALERT_HISTORY = 100; // Keep last 100 alerts per worker
// Resource thresholds
const THRESHOLDS = {
    cpu: { warning: 70, critical: 90 },
    memory: { warning: 75, critical: 85 },
    disk: { warning: 80, critical: 90 },
    costPerHour: { warning: 10, critical: 50 },
};
// Store previous CPU measurements for calculating real-time usage
let previousCpuTimes = null;
/**
 * Helper: Calculate CPU usage percentage (real-time)
 */
const calculateCpuUsage = () => {
    const os = getOsModule();
    if (!os?.cpus)
        return 0;
    try {
        const cpus = os.cpus();
        let totalIdle = 0;
        let totalTick = 0;
        cpus.forEach((cpu) => {
            for (const type in cpu.times) {
                totalTick += cpu.times[type];
            }
            totalIdle += cpu.times.idle;
        });
        const now = Date.now();
        // If we have previous measurements, calculate real-time usage
        if (previousCpuTimes) {
            const timeDiff = now - previousCpuTimes.timestamp;
            // Only calculate if enough time has passed (minimum 100ms)
            if (timeDiff >= 100) {
                const idleDiff = totalIdle - previousCpuTimes.idle;
                const totalDiff = totalTick - previousCpuTimes.total;
                // Calculate CPU usage percentage for this interval
                const cpuPercentage = totalDiff > 0 ? ((totalDiff - idleDiff) / totalDiff) * 100 : 0;
                // Update previous measurements
                previousCpuTimes = { idle: totalIdle, total: totalTick, timestamp: now };
                return Math.min(100, Math.max(0, cpuPercentage));
            }
        }
        // First measurement or not enough time passed
        previousCpuTimes = { idle: totalIdle, total: totalTick, timestamp: now };
        // For first call, return a reasonable estimate or use load average
        const loadAvg = safeLoadAverage();
        const cpuCount = safeCpuCount();
        return Math.min(100, Math.max(0, (loadAvg[0] / cpuCount) * 100));
    }
    catch (error) {
        Logger.error('Failed to calculate system CPU usage', error);
        return 0;
    }
};
/**
 * Helper: Get memory usage
 */
const getMemoryUsage = () => {
    const totalMemory = safeTotalMemory();
    const freeMemory = safeFreeMemory();
    const usedMemory = totalMemory - freeMemory;
    const usage = totalMemory > 0 ? (usedMemory / totalMemory) * 100 : 0;
    return {
        total: totalMemory,
        used: usedMemory,
        free: freeMemory,
        usage,
    };
};
/**
 * Helper: Capture resource snapshot
 */
const captureSnapshot = () => {
    const cpuUsage = calculateCpuUsage();
    const memoryUsage = getMemoryUsage();
    const loadAverage = safeLoadAverage();
    const cpuCores = safeCpuCount();
    return {
        timestamp: new Date(),
        cpu: {
            usage: cpuUsage,
            loadAverage,
            cores: cpuCores,
        },
        memory: memoryUsage,
        disk: {
            read: 0, // Would need platform-specific implementation
            write: 0,
        },
        network: {
            received: 0, // Would need platform-specific implementation
            transmitted: 0,
        },
        process: {
            pid: process.pid,
            uptime: process.uptime(),
            memoryUsage: process.memoryUsage(),
            cpuUsage: safeProcessCpuUsage(),
        },
    };
};
/**
 * Helper: Calculate cost based on resource usage
 */
const calculateCost = (snapshot, useSpotDiscount = false) => {
    const { cpu, memory } = snapshot;
    // CPU cost (based on cores and usage)
    const cpuCostPerHour = cpu.cores * (cpu.usage / 100) * costConfig.computeCostPerCoreHour;
    // Memory cost (based on GB used)
    const memoryGB = memory.used / (1024 * 1024 * 1024);
    const memoryCostPerHour = memoryGB * costConfig.memoryCostPerGBHour;
    // Total compute cost
    let totalCostPerHour = cpuCostPerHour + memoryCostPerHour;
    // Apply spot instance discount if applicable
    if (useSpotDiscount) {
        totalCostPerHour *= 1 - costConfig.spotInstanceDiscount / 100;
    }
    return {
        perHour: totalCostPerHour,
        perDay: totalCostPerHour * 24,
        perMonth: totalCostPerHour * 24 * 30,
    };
};
/**
 * Helper: Calculate efficiency score
 */
const calculateEfficiency = (snapshot) => {
    const { cpu, memory } = snapshot;
    // CPU efficiency: 50-80% usage is ideal
    let cpuEfficiency;
    if (cpu.usage < 30) {
        cpuEfficiency = cpu.usage * 2; // Under-utilized
    }
    else if (cpu.usage > 80) {
        cpuEfficiency = 100 - (cpu.usage - 80) * 2; // Over-utilized
    }
    else {
        cpuEfficiency = 100; // Ideal range
    }
    // Memory efficiency: 50-75% usage is ideal
    let memoryEfficiency;
    if (memory.usage < 40) {
        memoryEfficiency = memory.usage * 1.5; // Under-utilized
    }
    else if (memory.usage > 75) {
        memoryEfficiency = 100 - (memory.usage - 75) * 2; // Over-utilized
    }
    else {
        memoryEfficiency = 100; // Ideal range
    }
    const overallScore = cpuEfficiency * 0.6 + memoryEfficiency * 0.4;
    return {
        cpuEfficiency: Math.round(cpuEfficiency),
        memoryEfficiency: Math.round(memoryEfficiency),
        overallScore: Math.round(overallScore),
    };
};
/**
 * Helper: Check thresholds and create alerts
 */
const checkThresholds = (workerName, snapshot, cost) => {
    const alerts = [];
    // CPU alerts
    if (snapshot.cpu.usage >= THRESHOLDS.cpu.critical) {
        alerts.push({
            timestamp: new Date(),
            workerName,
            alertType: 'cpu-high',
            severity: 'critical',
            message: `Critical CPU usage: ${snapshot.cpu.usage.toFixed(1)}%`,
            currentValue: snapshot.cpu.usage,
            threshold: THRESHOLDS.cpu.critical,
            recommendation: 'Consider scaling up or optimizing worker code',
        });
    }
    else if (snapshot.cpu.usage >= THRESHOLDS.cpu.warning) {
        alerts.push({
            timestamp: new Date(),
            workerName,
            alertType: 'cpu-high',
            severity: 'warning',
            message: `High CPU usage: ${snapshot.cpu.usage.toFixed(1)}%`,
            currentValue: snapshot.cpu.usage,
            threshold: THRESHOLDS.cpu.warning,
            recommendation: 'Monitor closely and consider scaling',
        });
    }
    // Memory alerts
    if (snapshot.memory.usage >= THRESHOLDS.memory.critical) {
        alerts.push({
            timestamp: new Date(),
            workerName,
            alertType: 'memory-high',
            severity: 'critical',
            message: `Critical memory usage: ${snapshot.memory.usage.toFixed(1)}%`,
            currentValue: snapshot.memory.usage,
            threshold: THRESHOLDS.memory.critical,
            recommendation: 'Increase memory allocation or optimize memory usage',
        });
    }
    else if (snapshot.memory.usage >= THRESHOLDS.memory.warning) {
        alerts.push({
            timestamp: new Date(),
            workerName,
            alertType: 'memory-high',
            severity: 'warning',
            message: `High memory usage: ${snapshot.memory.usage.toFixed(1)}%`,
            currentValue: snapshot.memory.usage,
            threshold: THRESHOLDS.memory.warning,
            recommendation: 'Monitor memory consumption',
        });
    }
    // Cost alerts
    if (cost.perHour >= THRESHOLDS.costPerHour.critical) {
        alerts.push({
            timestamp: new Date(),
            workerName,
            alertType: 'cost-high',
            severity: 'critical',
            message: `Critical hourly cost: $${cost.perHour.toFixed(2)}/hr`,
            currentValue: cost.perHour,
            threshold: THRESHOLDS.costPerHour.critical,
            recommendation: 'Review resource allocation and consider cost optimization',
        });
    }
    else if (cost.perHour >= THRESHOLDS.costPerHour.warning) {
        alerts.push({
            timestamp: new Date(),
            workerName,
            alertType: 'cost-high',
            severity: 'warning',
            message: `High hourly cost: $${cost.perHour.toFixed(2)}/hr`,
            currentValue: cost.perHour,
            threshold: THRESHOLDS.costPerHour.warning,
            recommendation: 'Consider using spot instances or reducing concurrency',
        });
    }
    return alerts;
};
/**
 * Helper: Store alert
 */
const storeAlert = (alert) => {
    let history = alertHistory.get(alert.workerName);
    if (!history) {
        history = [];
        alertHistory.set(alert.workerName, history);
    }
    history.push(alert);
    // Trim alert history to prevent memory leaks
    if (history.length > MAX_ALERT_HISTORY) {
        alertHistory.set(alert.workerName, history.slice(-MAX_ALERT_HISTORY));
    }
};
/**
 * Helper: Calculate trend
 */
const calculateTrend = (workerName, metric, period) => {
    const history = resourceHistory.get(workerName);
    if (!history || history.length < 2)
        return null;
    const now = Date.now();
    let periodMs;
    switch (period) {
        case 'hour':
            periodMs = 60 * 60 * 1000;
            break;
        case 'day':
            periodMs = 24 * 60 * 60 * 1000;
            break;
        case 'week':
            periodMs = 7 * 24 * 60 * 60 * 1000;
            break;
    }
    // Filter snapshots within period
    const periodSnapshots = history.filter((s) => now - s.timestamp.getTime() <= periodMs);
    if (periodSnapshots.length < 2)
        return null;
    // Get metric values
    const values = periodSnapshots.map((s) => {
        switch (metric) {
            case 'cpu':
                return s.cpu.usage;
            case 'memory':
                return s.memory.usage;
            case 'disk':
                return s.disk.read + s.disk.write;
            case 'network':
                return s.network.received + s.network.transmitted;
            case 'cost':
                return calculateCost(s).perHour;
        }
    });
    // Simple linear regression for trend
    const firstValue = values[0];
    const lastValue = values[values.length - 1] ?? values[0];
    const changePercentage = ((lastValue - firstValue) / firstValue) * 100;
    let trend;
    if (Math.abs(changePercentage) < 5) {
        trend = 'stable';
    }
    else if (changePercentage > 0) {
        trend = 'increasing';
    }
    else {
        trend = 'decreasing';
    }
    // Simple predictions (linear extrapolation)
    const avgChange = (lastValue - firstValue) / periodSnapshots.length;
    const predictions = {
        nextHour: lastValue + avgChange * 12, // Assuming 5-min intervals
        nextDay: lastValue + avgChange * 288,
        nextWeek: lastValue + avgChange * 2016,
    };
    return {
        workerName,
        metric,
        period,
        trend,
        changePercentage,
        predictions,
    };
};
/**
 * Resource Monitor - Sealed namespace
 */
export const ResourceMonitor = Object.freeze({
    /**
     * Initialize resource monitor
     */
    initialize(config) {
        if (config) {
            costConfig = { ...DEFAULT_COST_CONFIG, ...config };
        }
        Logger.info('ResourceMonitor initialized', { costConfig });
    },
    /**
     * Check whether monitoring is running
     */
    isRunning() {
        return monitoringInterval !== null;
    },
    /**
     * Start monitoring
     */
    start(intervalSeconds = 30) {
        const globalResourceMonitoring = Env.getBool('WORKER_RESOURCE_MONITORING', false);
        if (!globalResourceMonitoring) {
            Logger.warn('ResourceMonitor disabled (WORKER_RESOURCE_MONITORING=false)');
            return;
        }
        if (monitoringInterval) {
            Logger.warn('ResourceMonitor already running');
            return;
        }
        monitoringInterval = setInterval(() => {
            const snapshot = captureSnapshot();
            // Store snapshot for later analysis
            // This would typically be saved to a time-series database
            Logger.debug('Resource snapshot captured', {
                cpu: snapshot.cpu.usage.toFixed(1) + '%',
                memory: snapshot.memory.usage.toFixed(1) + '%',
            });
        }, intervalSeconds * 1000);
        Logger.info('ResourceMonitor started', { intervalSeconds });
    },
    /**
     * Stop monitoring
     */
    stop() {
        if (monitoringInterval) {
            clearInterval(monitoringInterval);
            monitoringInterval = null;
            Logger.info('ResourceMonitor stopped');
        }
    },
    /**
     * Get current resource usage
     */
    getCurrentUsage(workerName, useSpotDiscount = false) {
        const snapshot = captureSnapshot();
        const cost = calculateCost(snapshot, useSpotDiscount);
        const efficiency = calculateEfficiency(snapshot);
        // Store in history
        let history = resourceHistory.get(workerName);
        if (!history) {
            history = [];
            resourceHistory.set(workerName, history);
        }
        history.push(snapshot);
        // Trim resource history to prevent memory leaks
        if (history.length > MAX_HISTORY_SIZE) {
            resourceHistory.set(workerName, history.slice(-MAX_HISTORY_SIZE));
        }
        // Check thresholds
        const alerts = checkThresholds(workerName, snapshot, cost);
        alerts.forEach((element) => {
            storeAlert(element);
        });
        return {
            workerName,
            cpu: snapshot.cpu.usage,
            memory: {
                number: snapshot.memory.total,
                percent: snapshot.memory.usage,
                used: snapshot.memory.used,
                free: snapshot.memory.free,
            },
            cost: {
                hourly: cost.perHour,
                daily: cost.perDay,
            },
            resourceSnapshot: snapshot,
            estimatedCost: cost,
            efficiency,
        };
    },
    /**
     * Get resource history
     */
    getHistory(workerName, limit = 100) {
        const history = resourceHistory.get(workerName) ?? [];
        return history.slice(-limit).map((s) => ({ ...s }));
    },
    /**
     * Get alerts
     */
    getAlerts(workerName, limit = 100) {
        const history = alertHistory.get(workerName) ?? [];
        return history.slice(-limit).map((a) => ({ ...a }));
    },
    /**
     * Get trend analysis
     */
    getTrend(workerName, metric, period) {
        return calculateTrend(workerName, metric, period);
    },
    /**
     * Get all trends
     */
    getAllTrends(workerName, period) {
        return {
            cpu: calculateTrend(workerName, 'cpu', period),
            memory: calculateTrend(workerName, 'memory', period),
            disk: calculateTrend(workerName, 'disk', period),
            network: calculateTrend(workerName, 'network', period),
            cost: calculateTrend(workerName, 'cost', period),
        };
    },
    /**
     * Update cost configuration
     */
    updateCostConfig(config) {
        costConfig = { ...costConfig, ...config };
        Logger.info('Resource monitor cost config updated', { costConfig });
    },
    /**
     * Get cost configuration
     */
    getCostConfig() {
        return { ...costConfig };
    },
    /**
     * Calculate projected cost
     */
    calculateProjectedCost(cpuUsagePercent, memoryGB, hoursPerDay, useSpotDiscount = false) {
        const cpuCores = safeCpuCount();
        const cpuCostPerHour = cpuCores * (cpuUsagePercent / 100) * costConfig.computeCostPerCoreHour;
        const memoryCostPerHour = memoryGB * costConfig.memoryCostPerGBHour;
        let totalCostPerHour = cpuCostPerHour + memoryCostPerHour;
        if (useSpotDiscount) {
            totalCostPerHour *= 1 - costConfig.spotInstanceDiscount / 100;
        }
        return {
            daily: totalCostPerHour * hoursPerDay,
            monthly: totalCostPerHour * hoursPerDay * 30,
            yearly: totalCostPerHour * hoursPerDay * 365,
        };
    },
    /**
     * Get system information
     */
    getSystemInfo() {
        return {
            platform: safePlatform(),
            arch: safeArch(),
            hostname: safeHostname(),
            cpus: safeCpuCount(),
            totalMemory: safeTotalMemory(),
            freeMemory: safeFreeMemory(),
            uptime: safeUptime(),
        };
    },
    /**
     * Clear history for a worker
     */
    clearHistory(workerName) {
        resourceHistory.delete(workerName);
        alertHistory.delete(workerName);
        Logger.info(`Cleared resource history for ${workerName}`);
    },
    /**
     * Shutdown
     */
    shutdown() {
        ResourceMonitor.stop();
        resourceHistory.clear();
        alertHistory.clear();
        Logger.info('ResourceMonitor shutdown complete');
    },
});
// Graceful shutdown handled by WorkerShutdown
