pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io

QtObject {
    id: manager

    property bool shellOpen: false
    property bool quickSettingsOpen: false
    property bool appLauncherOpen: false
    property bool powerMenuOpen: false
    property var appUsageCounts: ({})
    property string appUsagePath: {
        var homeDir = Quickshell.env("HOME");
        return homeDir ? homeDir + "/.local/share/deltarunequickshell/apps.json" : "";
    }
    property bool appUsageLoaded: false
    property var windowRequests: ({})
    property var quickSettingsPayload: ({})
    property var defaultGlobals: ({
        "notifications.stackPreviewEnabled": true,
        "shell.mprisOverlayEnabled": true
    })
    property var globals: Object.assign({}, defaultGlobals)
    property string globalsPath: {
        var homeDir = Quickshell.env("HOME");
        return homeDir ? homeDir + "/.local/share/deltarunequickshell/globals.json" : "";
    }
    property bool globalsLoaded: false

    signal shellOpened
    signal shellClosed
    signal quickSettingsOpened
    signal quickSettingsClosed
    signal appLauncherOpened
    signal appLauncherClosed
    signal powerMenuOpened
    signal powerMenuClosed
    signal windowRequested(string name, var payload)

    function openShell() {
        if (!shellOpen) {
            console.log("ShellStateManager: openShell");
            Hyprland.dispatch("submap deltarune");
            shellOpen = true;
            shellOpened();
        }
    }

    function closeShell() {
        if (shellOpen) {
            console.log("ShellStateManager: closeShell");
            Hyprland.dispatch("submap reset");
            if (quickSettingsOpen) {
                closeQuickSettings();
            }
            if (appLauncherOpen) {
                closeAppLauncher();
            }
            if (powerMenuOpen) {
                closePowerMenu();
            }
            shellOpen = false;
            shellClosed();
        }
    }

    function toggleShell() {
        shellOpen ? closeShell() : openShell();
    }

    function requestWindow(name, payload) {
        console.log("ShellStateManager: requestWindow", name, payload);
        windowRequests[name] = {
            payload: payload,
            timestamp: Date.now()
        };
        windowRequested(name, payload);
    }

    function openQuickSettings(payload) {
        var normalizedPayload = payload || ({});
        quickSettingsPayload = normalizedPayload;
        console.log("ShellStateManager: openQuickSettings", normalizedPayload);
        if (appLauncherOpen) {
            closeAppLauncher();
        }
        if (powerMenuOpen) {
            closePowerMenu();
        }
        if (!quickSettingsOpen) {
            quickSettingsOpen = true;
            quickSettingsOpened();
        }
        requestWindow("quickSettings", normalizedPayload);
    }

    function closeQuickSettings() {
        if (quickSettingsOpen) {
            console.log("ShellStateManager: closeQuickSettings");
            quickSettingsOpen = false;
            quickSettingsClosed();
        }
    }

    function toggleQuickSettings(payload) {
        quickSettingsOpen ? closeQuickSettings() : openQuickSettings(payload);
    }

    function openAppLauncher(payload) {
        var normalizedPayload = payload || ({});
        console.log("ShellStateManager: openAppLauncher", normalizedPayload);
        if (quickSettingsOpen) {
            closeQuickSettings();
        }
        if (powerMenuOpen) {
            closePowerMenu();
        }
        if (!appLauncherOpen) {
            appLauncherOpen = true;
            appLauncherOpened();
        }
        requestWindow("appLauncher", normalizedPayload);
    }

    function closeAppLauncher() {
        if (appLauncherOpen) {
            console.log("ShellStateManager: closeAppLauncher");
            appLauncherOpen = false;
            appLauncherClosed();
        }
    }

    function toggleAppLauncher(payload) {
        appLauncherOpen ? closeAppLauncher() : openAppLauncher(payload);
    }

    function openPowerMenu(payload) {
        var normalizedPayload = payload || ({});
        console.log("ShellStateManager: openPowerMenu", normalizedPayload);
        if (quickSettingsOpen) {
            closeQuickSettings();
        }
        if (appLauncherOpen) {
            closeAppLauncher();
        }
        if (!powerMenuOpen) {
            powerMenuOpen = true;
            powerMenuOpened();
        }
        requestWindow("powerMenu", normalizedPayload);
    }

    function closePowerMenu() {
        if (powerMenuOpen) {
            console.log("ShellStateManager: closePowerMenu");
            powerMenuOpen = false;
            powerMenuClosed();
        }
    }

    function togglePowerMenu(payload) {
        powerMenuOpen ? closePowerMenu() : openPowerMenu(payload);
    }

    function bumpAppUsage(id) {
        if (!id)
            return;
        var updated = Object.assign({}, appUsageCounts);
        updated[id] = (updated[id] || 0) + 1;
        appUsageCounts = updated;
    }

    function persistAppUsage() {
        if (!appUsageLoaded)
            return;
        if (!appUsageFile || !appUsageAdapter)
            return;
        appUsageAdapter.counts = appUsageCounts || ({});
        appUsageFile.writeAdapter();
    }

    function persistGlobals() {
        if (!globalsLoaded)
            return;
        if (!globalsFile || !globalsAdapter)
            return;
        globalsAdapter.values = globals || ({});
        globalsFile.writeAdapter();
    }

    onAppUsageCountsChanged: persistAppUsage()
    onGlobalsChanged: persistGlobals()

    property FileView appUsageFile: FileView {
        id: appUsageFile
        path: manager.appUsagePath
        watchChanges: true
        onFileChanged: reload()
        onLoaded: {
            if (appUsageAdapter) {
                manager.appUsageCounts = appUsageAdapter.counts || ({});
            }
            manager.appUsageLoaded = true;
        }
        onLoadFailed: {
            manager.appUsageLoaded = true;
            manager.persistAppUsage();
        }

        JsonAdapter {
            id: appUsageAdapter
            property var counts: ({})
        }
    }

    property FileView globalsFile: FileView {
        id: globalsFile
        path: manager.globalsPath
        watchChanges: true
        onFileChanged: reload()
        onLoaded: {
            var loaded = globalsAdapter && globalsAdapter.values ? globalsAdapter.values : ({});
            manager.globals = Object.assign({}, manager.defaultGlobals, loaded);
            manager.globalsLoaded = true;
        }
        onLoadFailed: {
            manager.globals = Object.assign({}, manager.defaultGlobals);
            manager.globalsLoaded = true;
            manager.persistGlobals();
        }

        JsonAdapter {
            id: globalsAdapter
            property var values: ({})
        }
    }

    function setGlobal(key, value) {
        var updated = Object.assign({}, globals);
        updated[key] = value;
        globals = updated;
    }

    function global(key, defaultValue) {
        return Object.prototype.hasOwnProperty.call(globals, key) ? globals[key] : defaultValue;
    }

    function notificationStackPreviewEnabled() {
        return Boolean(global("notifications.stackPreviewEnabled", true));
    }

    function setNotificationStackPreviewEnabled(enabled) {
        setGlobal("notifications.stackPreviewEnabled", Boolean(enabled));
    }

    function toggleNotificationStackPreviewEnabled() {
        setNotificationStackPreviewEnabled(!notificationStackPreviewEnabled());
    }

    function mprisOverlayEnabled() {
        return Boolean(global("shell.mprisOverlayEnabled", true));
    }

    function setMprisOverlayEnabled(enabled) {
        setGlobal("shell.mprisOverlayEnabled", Boolean(enabled));
    }

    function toggleMprisOverlayEnabled() {
        setMprisOverlayEnabled(!mprisOverlayEnabled());
    }
}
