pragma Singleton

import QtQuick
import Quickshell
import Quickshell.Io
import qs.modules.common

Singleton {
    // Array of CPU core usage percentages (0.0 to 1.0), one per core
    property var coreUsages: []

    // Overall CPU usage percentage (0.0 to 1.0), average across all cores
    property real overallUsage: 0.0

    // Previous /proc/stat values for delta calculations
    property var prevStats: []

    // Top processes, array of {pid: int, comm: string, cpu: float}
    property var topProcesses: []

    // Load average values (1-min, 5-min, 15-min)
    property var loadAvg: []

    // Number of top processes to show
    property int numTopProcesses: Config.data.cpu.numTopProcesses || 5

    Process {
        id: psProc
        command: ["sh", "-c", `ps -eo pid,comm,%cpu --sort=-%cpu --no-headers | head -${numTopProcesses+10}`]
        stdout: StdioCollector {
            onStreamFinished: {
                let lines = this.text.split('\n').filter(l => l.trim() !== '');
                let tp = [];
                for (let line of lines) {
                    if (tp.length == numTopProcesses) break;
                    let parts = line.trim().split(/\s+/);
                    if (parts.length === 3) {
                        let comm = parts[1];
                        if (comm === 'ps') continue;  // Skip ps itself
                        let pid = parseInt(parts[0]);
                        let cpu = parseFloat(parts[2]);
                        tp.push({pid: pid, comm: comm, cpu: cpu});
                    }
                }
                topProcesses = tp;
            }
        }
    }

    Process {
        id: loadAvgProc
        command: ["uptime"]
        stdout: StdioCollector {
            onStreamFinished: {
                let line = this.text.trim();
                let parts = line.split("load average:");
                if (parts.length > 1) {
                    let loads = parts[1].trim().split(',').map(s => parseFloat(s.trim()));
                    if (loads.length >= 3) {
                        loadAvg = loads;
                    }
                }
            }
        }
    }

    FileView {
        id: statFile
        path: "/proc/stat"
        onLoadFailed: function(error) {
            console.log("CPU Service: FileView load failed for /proc/stat:", error);
        }
    }

    Timer {
        interval: Config.data.cpu.updateInterval
        running: true
        repeat: true
        triggeredOnStart: true
        onTriggered: {
            updateCpuUsage()
            psProc.running = true
            loadAvgProc.running = true
        }
    }

    function updateCpuUsage() {
        statFile.reload();
        let content = statFile.text();

        if (content === "") {
            return;
        }

        let lines = content.split('\n');
        let currentStats = [];

        // Parse lines starting with "cpu" (cpu, cpu0, cpu1, ...)
        for (let i = 0; i < lines.length; ++i) {
            let line = lines[i].trim();
            if (line.startsWith('cpu')) {
                let parts = line.split(/\s+/);
                if (parts.length >= 8) {
                    let user = parseInt(parts[1]);
                    let nice = parseInt(parts[2]);
                    let system = parseInt(parts[3]);
                    let idle = parseInt(parts[4]);
                    let iowait = parseInt(parts[5]);
                    let irq = parseInt(parts[6]);
                    let softirq = parseInt(parts[7]);
                    // Total ticks: sum of all except idle for denominator
                    let total = user + nice + system + idle + iowait + irq + softirq;
                    currentStats.push({ total: total, idle: idle });
                }
            }
        }

        if (prevStats.length === currentStats.length && prevStats.length > 0) {
            let totalUsage = 0.0;
            let coreUsagesTemp = [];

            // Calculate for each core (skip overall "cpu")
            for (let j = 1; j < currentStats.length; ++j) {
                let current = currentStats[j];
                let prev = prevStats[j];
                let deltaTotal = current.total - prev.total;
                let deltaIdle = current.idle - prev.idle;
                let usage = (deltaTotal > 0) ? (deltaTotal - deltaIdle) / deltaTotal : 0.0;
                usage = Math.min(Math.max(usage, 0.0), 1.0);
                coreUsagesTemp.push(usage);
            }

            // Overall usage
            let overallCurrent = currentStats[0];
            let overallPrev = prevStats[0];
            let overallDeltaTotal = overallCurrent.total - overallPrev.total;
            let overallDeltaIdle = overallCurrent.idle - overallPrev.idle;
            totalUsage = (overallDeltaTotal > 0) ? (overallDeltaTotal - overallDeltaIdle) / overallDeltaTotal : 0.0;
            totalUsage = Math.min(Math.max(totalUsage, 0.0), 1.0);

            coreUsages = coreUsagesTemp;
            overallUsage = totalUsage;
        } else if (prevStats.length === 0) {
            // First run: Store baselines
            prevStats = currentStats;
        }

        prevStats = currentStats;
    }
}