import { execFileSync, execSync } from "node:child_process";
import os from "node:os";
import { createLogger } from "../utils/logger.js";
const log = createLogger("system-metrics");
const CPU_SAMPLE_INTERVAL_MS = 120;
const BYTES_PER_GIB = 1024 ** 3;
let previousNetworkTotals = null;
function roundToTwo(value) {
    return Math.round(value * 100) / 100;
}
function clampPercent(value) {
    if (!Number.isFinite(value)) {
        return 0;
    }
    return roundToTwo(Math.min(100, Math.max(0, value)));
}
function bytesToGiB(value) {
    return roundToTwo(value / BYTES_PER_GIB);
}
function sumCpuTimes() {
    return os.cpus().reduce((snapshot, cpu) => {
        const total = Object.values(cpu.times).reduce((sum, time) => sum + time, 0);
        return {
            idle: snapshot.idle + cpu.times.idle,
            total: snapshot.total + total,
        };
    }, { idle: 0, total: 0 });
}
function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}
/**
 * 采样整机 CPU 使用率。
 * 主流程：读取两次 CPU times -> 计算非 idle 增量占比 -> 返回核心数与型号信息。
 */
async function collectCpuMetrics() {
    const before = sumCpuTimes();
    await wait(CPU_SAMPLE_INTERVAL_MS);
    const after = sumCpuTimes();
    const totalDelta = after.total - before.total;
    const idleDelta = after.idle - before.idle;
    const usagePercent = totalDelta <= 0 ? 0 : ((totalDelta - idleDelta) / totalDelta) * 100;
    const cpus = os.cpus();
    return {
        usagePercent: clampPercent(usagePercent),
        coreCount: cpus.length,
        model: cpus[0]?.model || os.arch(),
    };
}
function collectMemoryMetrics() {
    const totalBytes = os.totalmem();
    const freeBytes = os.freemem();
    const usedBytes = Math.max(0, totalBytes - freeBytes);
    return {
        usedBytes,
        freeBytes,
        totalBytes,
        usagePercent: totalBytes > 0 ? clampPercent((usedBytes / totalBytes) * 100) : 0,
    };
}
function resolveStorageProbePath() {
    return process.env.AWS_SYSTEM_METRICS_STORAGE_PATH || process.cwd();
}
function collectWindowsDiskUsage(targetPath) {
    const root = os.platform() === "win32" ? targetPath.slice(0, 2).toUpperCase() : targetPath;
    const script = `Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='${root.replace(/'/g, "''")}'" | Select-Object Size,FreeSpace | ConvertTo-Json -Compress`;
    const output = execFileSync("powershell", ["-NoProfile", "-NonInteractive", "-Command", script], { encoding: "utf8", timeout: 5000, windowsHide: true }).trim();
    const parsed = JSON.parse(output);
    return {
        freeBytes: Number(parsed.FreeSpace || 0),
        totalBytes: Number(parsed.Size || 0),
    };
}
function collectUnixDiskUsage(targetPath) {
    const output = execFileSync("df", ["-kP", targetPath], {
        encoding: "utf8",
        timeout: 5000,
    }).trim();
    const lines = output.split(/\r?\n/).filter(Boolean);
    const columns = lines[1]?.trim().split(/\s+/) || [];
    const totalKiB = Number(columns[1] || 0);
    const usedKiB = Number(columns[2] || 0);
    const freeKiB = Number(columns[3] || Math.max(0, totalKiB - usedKiB));
    return {
        freeBytes: freeKiB * 1024,
        totalBytes: totalKiB * 1024,
    };
}
/**
 * 采集工作区所在磁盘容量。
 * 主流程：优先查询当前工作目录所在卷 -> 失败时回退为 0，避免影响终端主流程。
 */
function collectStorageMetrics() {
    const targetPath = resolveStorageProbePath();
    try {
        const usage = os.platform() === "win32"
            ? collectWindowsDiskUsage(targetPath)
            : collectUnixDiskUsage(targetPath);
        const totalBytes = Math.max(0, usage.totalBytes);
        const freeBytes = Math.max(0, usage.freeBytes);
        const usedBytes = Math.max(0, totalBytes - freeBytes);
        return {
            path: targetPath,
            usedBytes,
            freeBytes,
            totalBytes,
            usagePercent: totalBytes > 0 ? clampPercent((usedBytes / totalBytes) * 100) : 0,
            freeGiB: bytesToGiB(freeBytes),
            totalGiB: bytesToGiB(totalBytes),
        };
    }
    catch (error) {
        log.debug("Failed to collect storage metrics:", error);
        return {
            path: targetPath,
            usedBytes: 0,
            freeBytes: 0,
            totalBytes: 0,
            usagePercent: 0,
            freeGiB: 0,
            totalGiB: 0,
        };
    }
}
function collectLinuxNetworkTotals() {
    try {
        const output = execSync("cat /proc/net/dev", { encoding: "utf8", timeout: 5000 });
        let uploadTotalBytes = 0;
        let downloadTotalBytes = 0;
        for (const line of output.split(/\r?\n/)) {
            const [rawName, rawValues] = line.split(":");
            if (!rawName || !rawValues) {
                continue;
            }
            const name = rawName.trim();
            if (!name || name === "lo") {
                continue;
            }
            const values = rawValues.trim().split(/\s+/).map(Number);
            downloadTotalBytes += Number.isFinite(values[0]) ? values[0] : 0;
            uploadTotalBytes += Number.isFinite(values[8]) ? values[8] : 0;
        }
        return { uploadTotalBytes, downloadTotalBytes };
    }
    catch (error) {
        log.debug("Failed to collect Linux network metrics:", error);
        return null;
    }
}
function collectDarwinNetworkTotals() {
    try {
        const output = execFileSync("netstat", ["-ibn"], { encoding: "utf8", timeout: 5000 });
        const seen = new Set();
        let uploadTotalBytes = 0;
        let downloadTotalBytes = 0;
        for (const line of output.split(/\r?\n/).slice(1)) {
            const columns = line.trim().split(/\s+/);
            const name = columns[0];
            if (!name || name === "lo0" || seen.has(name)) {
                continue;
            }
            const inputBytes = Number(columns[6] || 0);
            const outputBytes = Number(columns[9] || 0);
            downloadTotalBytes += Number.isFinite(inputBytes) ? inputBytes : 0;
            uploadTotalBytes += Number.isFinite(outputBytes) ? outputBytes : 0;
            seen.add(name);
        }
        return { uploadTotalBytes, downloadTotalBytes };
    }
    catch (error) {
        log.debug("Failed to collect macOS network metrics:", error);
        return null;
    }
}
function collectWindowsNetworkTotals() {
    try {
        const script = "Get-NetAdapterStatistics | Select-Object ReceivedBytes,SentBytes | ConvertTo-Json -Compress";
        const output = execFileSync("powershell", ["-NoProfile", "-NonInteractive", "-Command", script], { encoding: "utf8", timeout: 5000, windowsHide: true }).trim();
        if (!output) {
            return null;
        }
        const parsed = JSON.parse(output);
        const rows = Array.isArray(parsed) ? parsed : [parsed];
        return rows.reduce((totals, row) => ({
            downloadTotalBytes: totals.downloadTotalBytes + Number(row.ReceivedBytes || 0),
            uploadTotalBytes: totals.uploadTotalBytes + Number(row.SentBytes || 0),
        }), { uploadTotalBytes: 0, downloadTotalBytes: 0 });
    }
    catch (error) {
        log.debug("Failed to collect Windows network metrics:", error);
        return null;
    }
}
function collectNetworkTotals() {
    const platform = os.platform();
    const totals = platform === "win32"
        ? collectWindowsNetworkTotals()
        : platform === "darwin"
            ? collectDarwinNetworkTotals()
            : collectLinuxNetworkTotals();
    return {
        uploadTotalBytes: totals?.uploadTotalBytes || 0,
        downloadTotalBytes: totals?.downloadTotalBytes || 0,
        sampledAt: Date.now(),
    };
}
/**
 * 采集网络上下行速率。
 * 主流程：读取累计收发字节 -> 与上次采样做时间差分 -> 首次采样速率为 0。
 */
function collectNetworkMetrics() {
    const current = collectNetworkTotals();
    const previous = previousNetworkTotals;
    previousNetworkTotals = current;
    if (!previous) {
        return {
            uploadBytesPerSecond: 0,
            downloadBytesPerSecond: 0,
            uploadTotalBytes: current.uploadTotalBytes,
            downloadTotalBytes: current.downloadTotalBytes,
        };
    }
    const elapsedSeconds = Math.max(1, (current.sampledAt - previous.sampledAt) / 1000);
    return {
        uploadBytesPerSecond: Math.max(0, Math.round((current.uploadTotalBytes - previous.uploadTotalBytes) / elapsedSeconds)),
        downloadBytesPerSecond: Math.max(0, Math.round((current.downloadTotalBytes - previous.downloadTotalBytes) / elapsedSeconds)),
        uploadTotalBytes: current.uploadTotalBytes,
        downloadTotalBytes: current.downloadTotalBytes,
    };
}
/**
 * 汇总机器关键指标快照。
 * 主流程：并行采集内存/存储/网络，CPU 做短采样后合并为前端可展示结构。
 */
export async function collectSystemMetrics() {
    const [cpu, memory, storage, network] = await Promise.all([
        collectCpuMetrics(),
        Promise.resolve(collectMemoryMetrics()),
        Promise.resolve(collectStorageMetrics()),
        Promise.resolve(collectNetworkMetrics()),
    ]);
    return {
        ok: true,
        collectedAt: new Date().toISOString(),
        cpu,
        memory,
        storage,
        network,
    };
}
