pragma Singleton

// The system power profile: power-saver, balanced, or performance.
//
// The same daemon GNOME's Power panel drives. On Fedora 44 the implementation
// is tuned-ppd rather than power-profiles-daemon, but it serves the same
// net.hadess.PowerProfiles interface -- so this talks to the interface, not to
// either binary. powerprofilesctl is not installed here at all.
//
// Not a stored preference. The profile lives in the daemon, survives Panama
// restarts, and can be changed by anything else on the system; keeping a copy
// in settings.json would mean restoring a value the daemon had moved past.
// Same reasoning as monitor brightness.
//
// Read on demand and after each change. The daemon does emit PropertiesChanged,
// but subscribing to it would mean holding a bus connection open for a value
// that changes only when someone chooses it.

import Quickshell
import Quickshell.Io
import QtQuick

Singleton {
    id: root

    readonly property string helperPath: Quickshell.shellDir + "/scripts/panama-power-profile"

    property var profiles: []
    property string active: ""
    property bool scanned: false
    property bool busy: false
    property string lastError: ""

    // Non-empty when the machine cannot actually deliver the profile it is set
    // to -- thermal throttling, or a laptop running on battery. Worth showing,
    // because otherwise "performance" is a claim the hardware is not honouring.
    property string degraded: ""

    readonly property bool available: root.profiles.length > 0

    // Presentation lives here rather than in the page so the Control Center and
    // Settings cannot disagree about what a profile is called.
    function label(profile: string): string {
        switch (profile) {
        case "power-saver": return "Power Saver";
        case "balanced": return "Balanced";
        case "performance": return "Performance";
        default: return profile;
        }
    }

    function detail(profile: string): string {
        switch (profile) {
        case "power-saver": return "Reduces performance to save energy and run quieter";
        case "balanced": return "Standard behaviour, scaling up only when needed";
        case "performance": return "Holds higher clocks, using more power and making more noise";
        default: return "";
        }
    }

    function refresh(): void {
        if (!query.running)
            query.running = true;
    }

    function set(profile: string): void {
        if (root.busy || profile === root.active)
            return;
        root.busy = true;
        apply.command = [root.helperPath, "set", profile];
        apply.running = true;
    }

    Process {
        id: query
        command: [root.helperPath, "list"]
        stdout: StdioCollector {
            onStreamFinished: {
                try {
                    const parsed = JSON.parse(this.text);
                    root.profiles = Array.isArray(parsed.profiles) ? parsed.profiles : [];
                    root.active = String(parsed.active ?? "");
                    root.degraded = String(parsed.degraded ?? "");
                    root.lastError = String(parsed.error ?? "");
                } catch (error) {
                    root.profiles = [];
                    root.lastError = "Could not read the power profile helper's output.";
                    console.warn("PowerProfiles: could not parse helper output:", error);
                }
                root.scanned = true;
            }
        }
    }

    Process {
        id: apply
        stderr: StdioCollector {
            onStreamFinished: if (this.text.trim() !== "") root.lastError = this.text.trim()
        }
        // Re-read rather than assuming: the daemon may refuse, or may land on a
        // different profile than the one asked for.
        onExited: {
            root.busy = false;
            root.refresh();
        }
    }
}
