import Quickshell
import Quickshell.Io
import QtQuick

import qs.config
import qs.services

ShellRoot {
    id: root

    property var resetCalls: []
    property var appliedBatches: []
    property bool displayBlocked: false

    function recordReset(name: string): void {
        const next = root.resetCalls.slice();
        next.push(name);
        root.resetCalls = next;
    }

    Component.onCompleted: {
        // Keep compositor verification entirely inside the isolated harness.
        // Production applyOptions is covered separately by the Hyprland write
        // contract; this seam proves commit/reset routing without changing the
        // desktop that is running the test.
        if (Quickshell.env("PANAMA_SETTINGS_TEST_ISOLATE_COMPOSITOR") === "1") {
            SystemSettings.compositorApplyOverride = function(requested) {
                const batches = root.appliedBatches.slice();
                batches.push(requested);
                root.appliedBatches = batches;
                for (const key in requested)
                    DesktopPreferences.set(key, requested[key]);
                return true;
            };
        }
        SystemSettings.displayBusy = function() { return false; };
        SystemSettings.readDisplays = function() { return DesktopPreferences.get("displays"); };
        SystemSettings.protectDisplays = function(value) {
            root.recordReset("display.protect");
            return DesktopPreferences.set("displays", value);
        };
        SystemSettings.setDisplayBlocked = function(blocked) {
            root.recordReset("display.block:" + blocked);
            root.displayBlocked = blocked;
        };
        SystemSettings.reloadKeybinds = function() { root.recordReset("keybinds.reload"); };
        SystemSettings.keybindsReloading = function() { return false; };
        SystemSettings.applyWallpaper = function(path) { root.recordReset("wallpaper.set:" + path); };
    }

    IpcHandler {
        target: "settings-system-test"

        function refresh(): void { SystemSettings.refresh(); }

        // One batch, matching how the shell applies persisted policy. Three
        // separate setters would be refused as overlapping writes, since each
        // one is only complete after its value has been read back.
        function apply(autoHdr: bool, vrr: int, directScanout: int): void {
            SystemSettings.applyOptions({
                autoHdr: autoHdr,
                vrrPolicy: vrr,
                directScanoutPolicy: directScanout
            });
        }

        // Applies an arbitrary batch of schema keys, so the contract can cover
        // every getoption answer shape -- int, bool, float, str, and the css
        // box that gaps read back as -- not just the display policies.
        function applyJson(payload: string): bool {
            return SystemSettings.applyOptions(JSON.parse(payload));
        }

        // The routing entry point the settings rows use: a compositor-backed
        // key must be applied and verified before it is stored, a local one is
        // written directly. The contract checks both halves.
        function commit(key: string, payload: string): bool {
            return SystemSettings.commitPreference(key, JSON.parse(payload));
        }

        function stored(key: string): string {
            return JSON.stringify(DesktopPreferences.get(key));
        }

        function seedHome(): void {
            HomePreferences.favorites = [{ id: "light.contract_probe", alias: "Probe" }];
            HomePreferences.initialized = true;
        }

        function homeState(): string {
            return JSON.stringify({
                count: HomePreferences.favorites.length,
                initialized: HomePreferences.initialized
            });
        }

        function restoreDefaults(): bool {
            root.resetCalls = [];
            return SystemSettings.restoreDefaults();
        }

        function resetState(): string {
            return JSON.stringify({
                calls: root.resetCalls,
                displayBlocked: root.displayBlocked,
                appliedBatches: root.appliedBatches
            });
        }

        function applyState(): string {
            return JSON.stringify(root.appliedBatches);
        }

        function panelAllowed(panel: string): bool {
            return SystemSettings.isGnomePanelAllowed(panel);
        }

        function status(): string {
            return JSON.stringify({
                monitorName: SystemSettings.monitorName,
                monitorDescription: SystemSettings.monitorDescription,
                width: SystemSettings.monitorWidth,
                height: SystemSettings.monitorHeight,
                scale: SystemSettings.monitorScale,
                format: SystemSettings.monitorFormat,
                busy: SystemSettings.busy,
                lastError: SystemSettings.lastError
            });
        }
    }
}
