pragma Singleton
pragma ComponentBehavior: Bound

import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Services

Singleton {
    id: root
    readonly property var log: Log.scoped("PortalService")

    property bool accountsServiceAvailable: false
    property string systemProfileImage: ""
    property string profileImage: ""
    property bool settingsPortalAvailable: false
    property int systemColorScheme: 0
    property bool colorSchemeInitialized: false

    property bool freedeskAvailable: false
    property string colorSchemeCommand: ""
    property string pendingProfileImage: ""

    readonly property string socketPath: Quickshell.env("DMS_SOCKET")

    function init() {
    }

    function getSystemProfileImage() {
        if (!freedeskAvailable)
            return;
        const username = Quickshell.env("USER");
        if (!username)
            return;
        DMSService.sendRequest("freedesktop.accounts.getUserIconFile", {
            "username": username
        }, response => {
            if (response.result && response.result.success) {
                const iconFile = response.result.value || "";
                if (iconFile && iconFile !== "" && iconFile !== "/var/lib/AccountsService/icons/") {
                    systemProfileImage = iconFile;
                    if (!profileImage || profileImage === "") {
                        profileImage = iconFile;
                    }
                }
            }
        });
    }

    function getUserProfileImage(username) {
        if (!username) {
            profileImage = "";
            return;
        }

        if (!freedeskAvailable) {
            profileImage = "";
            return;
        }

        DMSService.sendRequest("freedesktop.accounts.getUserIconFile", {
            "username": username
        }, response => {
            if (response.result && response.result.success) {
                const icon = response.result.value || "";
                if (icon && icon !== "" && icon !== "/var/lib/AccountsService/icons/") {
                    profileImage = icon;
                } else {
                    profileImage = "";
                }
            } else {
                profileImage = "";
            }
        });
    }

    function setProfileImage(imagePath) {
        if (accountsServiceAvailable) {
            pendingProfileImage = imagePath;
            setSystemProfileImage(imagePath || "");
        } else {
            profileImage = imagePath;
        }
    }

    function canSyncColorScheme() {
        if (typeof SettingsData === "undefined" || !SettingsData.syncModeWithPortal)
            return false;
        if (!settingsPortalAvailable)
            return false;
        if (typeof SessionData !== "undefined" && SessionData.themeModeAutoEnabled)
            return false;
        return typeof Theme !== "undefined";
    }

    // Follow only genuine portal transitions, debounced by the settle window — the
    // opt-in GTK4-refresh toggle reverts within ~400ms, and a stale portal value
    // (broken gsettings→portal bridge) must never revert a DMS-initiated change.
    function handlePortalColorScheme(scheme) {
        const isTransition = colorSchemeInitialized && scheme !== systemColorScheme;
        colorSchemeInitialized = true;
        systemColorScheme = scheme;

        if (!canSyncColorScheme())
            return;

        const shouldBeLight = scheme !== 1;
        if (Theme.isLightMode === shouldBeLight) {
            colorSchemeSettleTimer.stop();
            return;
        }
        if (!isTransition)
            return;
        colorSchemeSettleTimer.restart();
    }

    Timer {
        id: colorSchemeSettleTimer
        interval: 750
        onTriggered: {
            if (!root.canSyncColorScheme())
                return;
            const shouldBeLight = root.systemColorScheme !== 1;
            if (Theme.isLightMode === shouldBeLight)
                return;
            if (Theme.workerRunning) {
                restart();
                return;
            }
            Theme.setLightMode(shouldBeLight, true, false);
        }
    }

    function setSystemColorScheme(isLightMode) {
        if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) {
            return;
        }

        const preferLight = isLightMode && systemColorScheme === 2;
        const targetScheme = isLightMode ? (preferLight ? "prefer-light" : "default") : "prefer-dark";

        switch (colorSchemeCommand) {
        case "gsettings":
            Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", targetScheme]);
            break;
        case "dconf":
            Quickshell.execDetached(["dconf", "write", "/org/gnome/desktop/interface/color-scheme", `'${targetScheme}'`]);
            break;
        }
    }

    function setSystemIconTheme(themeName) {
        if (!settingsPortalAvailable || !freedeskAvailable)
            return;
        DMSService.sendRequest("freedesktop.settings.setIconTheme", {
            "iconTheme": themeName
        }, response => {
            if (response.error) {
                log.warn("Failed to set icon theme:", response.error);
            }
        });
    }

    function setSystemProfileImage(imagePath) {
        if (!accountsServiceAvailable || !freedeskAvailable)
            return;
        DMSService.sendRequest("freedesktop.accounts.setIconFile", {
            "path": imagePath || ""
        }, response => {
            if (response.error) {
                log.warn("Failed to set icon file:", response.error);

                const errorMsg = response.error.toString();
                let userMessage = I18n.tr("Failed to set profile image");

                if (errorMsg.includes("too large")) {
                    userMessage = I18n.tr("Profile image is too large. Please use a smaller image.");
                } else if (errorMsg.includes("permission")) {
                    userMessage = I18n.tr("Permission denied to set profile image.");
                } else if (errorMsg.includes("not found") || errorMsg.includes("does not exist")) {
                    userMessage = I18n.tr("Selected image file not found.");
                } else {
                    userMessage = I18n.tr("Failed to set profile image: %1").arg(errorMsg.split(":").pop().trim());
                }

                Quickshell.execDetached(["notify-send", "-u", "normal", "-a", "DMS", "-i", "error", I18n.tr("Profile Image Error"), userMessage]);

                pendingProfileImage = "";
            } else {
                profileImage = pendingProfileImage;
                pendingProfileImage = "";
                Qt.callLater(() => getSystemProfileImage());
            }
        });
    }

    Component.onCompleted: {
        if (socketPath && socketPath.length > 0) {
            checkDMSCapabilities();
        } else {
            log.info("DMS_SOCKET not set");
        }
        colorSchemeDetector.running = true;
    }

    Connections {
        target: Theme

        function onIsLightModeChanged() {
            root.setSystemColorScheme(Theme.isLightMode);
        }
    }

    Connections {
        target: typeof SettingsData !== "undefined" ? SettingsData : null

        function onSyncModeWithPortalChanged() {
            if (!SettingsData.syncModeWithPortal)
                return;
            if (typeof Theme === "undefined")
                return;
            root.setSystemColorScheme(Theme.isLightMode);
        }
    }

    Connections {
        target: DMSService

        function onFreedesktopStateUpdate(data) {
            if (!data || !data.settings)
                return;
            root.settingsPortalAvailable = data.settings.available === true;
            root.handlePortalColorScheme(data.settings.colorScheme || 0);
        }
    }

    Connections {
        target: DMSService

        function onConnectionStateChanged() {
            if (DMSService.isConnected) {
                checkDMSCapabilities();
            }
        }
    }

    Connections {
        target: DMSService
        enabled: DMSService.isConnected

        function onCapabilitiesChanged() {
            checkDMSCapabilities();
        }
    }

    function checkDMSCapabilities() {
        if (!DMSService.isConnected) {
            return;
        }

        if (DMSService.capabilities.length === 0) {
            return;
        }

        freedeskAvailable = DMSService.capabilities.includes("freedesktop");
        if (freedeskAvailable) {
            checkAccountsService();
            checkSettingsPortal();
        } else {
            log.info("freedesktop capability not available in DMS");
        }
    }

    function checkAccountsService() {
        if (!freedeskAvailable)
            return;
        DMSService.sendRequest("freedesktop.getState", null, response => {
            if (response.result && response.result.accounts) {
                accountsServiceAvailable = response.result.accounts.available || false;
                if (accountsServiceAvailable) {
                    getSystemProfileImage();
                }
            }
        });
    }

    function checkSettingsPortal() {
        if (!freedeskAvailable)
            return;
        DMSService.sendRequest("freedesktop.getState", null, response => {
            if (response.result && response.result.settings) {
                settingsPortalAvailable = response.result.settings.available || false;
                handlePortalColorScheme(response.result.settings.colorScheme || 0);
            }
        });
    }

    Process {
        id: colorSchemeDetector
        command: ["bash", "-c", "command -v gsettings || command -v dconf"]
        running: false

        stdout: StdioCollector {
            onStreamFinished: {
                const cmd = text.trim();
                if (cmd.includes("gsettings")) {
                    root.colorSchemeCommand = "gsettings";
                } else if (cmd.includes("dconf")) {
                    root.colorSchemeCommand = "dconf";
                }
            }
        }
    }

    IpcHandler {
        target: "profile"

        function getImage(): string {
            return root.profileImage;
        }

        function setImage(path: string): string {
            if (!path) {
                return "ERROR: No path provided";
            }

            const absolutePath = path.startsWith("/") ? path : `${StandardPaths.writableLocation(StandardPaths.HomeLocation)}/${path}`;

            try {
                root.setProfileImage(absolutePath);
                return "SUCCESS: Profile image set to " + absolutePath;
            } catch (e) {
                return "ERROR: Failed to set profile image: " + e.toString();
            }
        }

        function clearImage(): string {
            root.setProfileImage("");
            return "SUCCESS: Profile image cleared";
        }
    }
}
