import QtQuick
import Quickshell
import qs.Common
import qs.Modals
import qs.Modals.Changelog
import qs.Modals.Clipboard
import qs.Modals.Greeter
import qs.Modals.Settings
import qs.Modals.DankLauncherV2
import qs.Modules
import qs.Modules.AppDrawer
import qs.Modules.DankDash
import qs.Modules.ControlCenter
import qs.Modules.Dock
import qs.Modules.Lock
import qs.Modules.Notepad
import qs.Modules.Notifications.Center
import qs.Widgets
import qs.Modules.Notifications.Popup
import qs.Modules.OSD
import qs.Modules.ProcessList
import qs.Modules.DankBar
import qs.Modules.DankBar.Popouts
import qs.Modules.WorkspaceOverlays
import qs.Services

Item {
    id: root

    Instantiator {
        id: daemonPluginInstantiator
        asynchronous: true
        model: Object.keys(PluginService.pluginDaemonComponents)

        delegate: Loader {
            id: daemonLoader
            property string pluginId: modelData
            sourceComponent: PluginService.pluginDaemonComponents[pluginId]

            onLoaded: {
                if (item) {
                    item.pluginService = PluginService;
                    if (item.popoutService !== undefined) {
                        item.popoutService = PopoutService;
                    }
                    item.pluginId = pluginId;
                    console.info("Daemon plugin loaded:", pluginId);
                }
            }
        }
    }

    Loader {
        id: blurredWallpaperBackgroundLoader
        active: SettingsData.blurredWallpaperLayer && CompositorService.isNiri
        asynchronous: false

        sourceComponent: BlurredWallpaperBackground {}
    }

    WallpaperBackground {}

    DesktopWidgetLayer {}

    Lock {
        id: lock
    }

    Variants {
        model: Quickshell.screens

        delegate: Loader {
            id: fadeWindowLoader
            required property var modelData
            active: SettingsData.fadeToLockEnabled
            asynchronous: false

            sourceComponent: FadeToLockWindow {
                screen: fadeWindowLoader.modelData

                onFadeCompleted: {
                    IdleService.lockRequested();
                }

                onFadeCancelled: {
                    console.log("Fade to lock cancelled by user on screen:", fadeWindowLoader.modelData.name);
                }
            }

            Connections {
                target: IdleService
                enabled: fadeWindowLoader.item !== null

                function onFadeToLockRequested() {
                    if (fadeWindowLoader.item) {
                        fadeWindowLoader.item.startFade();
                    }
                }

                function onCancelFadeToLock() {
                    if (fadeWindowLoader.item) {
                        fadeWindowLoader.item.cancelFade();
                    }
                }
            }
        }
    }

    Variants {
        model: Quickshell.screens

        delegate: Loader {
            id: fadeDpmsWindowLoader
            required property var modelData
            active: SettingsData.fadeToDpmsEnabled
            asynchronous: false

            sourceComponent: FadeToDpmsWindow {
                screen: fadeDpmsWindowLoader.modelData

                onFadeCompleted: {
                    IdleService.requestMonitorOff();
                }

                onFadeCancelled: {
                    console.log("Fade to DPMS cancelled by user on screen:", fadeDpmsWindowLoader.modelData.name);
                }
            }

            Connections {
                target: IdleService
                enabled: fadeDpmsWindowLoader.item !== null

                function onFadeToDpmsRequested() {
                    if (fadeDpmsWindowLoader.item) {
                        fadeDpmsWindowLoader.item.startFade();
                    }
                }

                function onCancelFadeToDpms() {
                    if (fadeDpmsWindowLoader.item) {
                        fadeDpmsWindowLoader.item.cancelFade();
                    }
                }

                function onRequestMonitorOn() {
                    if (!fadeDpmsWindowLoader.item)
                        return;
                    fadeDpmsWindowLoader.item.cancelFade();
                }
            }
        }
    }

    property string _barLayoutStateJson: {
        const configs = SettingsData.barConfigs;
        const mapped = configs.map(c => ({
                    id: c.id,
                    position: c.position,
                    autoHide: c.autoHide,
                    visible: c.visible
                })).sort((a, b) => {
            const aVertical = a.position === SettingsData.Position.Left || a.position === SettingsData.Position.Right;
            const bVertical = b.position === SettingsData.Position.Left || b.position === SettingsData.Position.Right;
            if (aVertical !== bVertical) {
                return aVertical - bVertical;
            }
            return String(a.id).localeCompare(String(b.id));
        });
        return JSON.stringify(mapped);
    }

    on_BarLayoutStateJsonChanged: {
        if (typeof dockRecreateDebounce !== "undefined") {
            dockRecreateDebounce.restart();
        }
    }

    Repeater {
        id: dankBarRepeater
        model: ScriptModel {
            id: barRepeaterModel
            values: JSON.parse(root._barLayoutStateJson)
        }

        property var hyprlandOverviewLoaderRef: hyprlandOverviewLoader

        delegate: Loader {
            id: barLoader
            required property var modelData
            property var barConfig: SettingsData.barConfigs.find(cfg => cfg.id === modelData.id) || null
            active: barConfig?.enabled ?? false
            asynchronous: false

            sourceComponent: DankBar {
                barConfig: barLoader.barConfig
                hyprlandOverviewLoader: dankBarRepeater.hyprlandOverviewLoaderRef

                onColorPickerRequested: {
                    if (colorPickerModal.shouldBeVisible) {
                        colorPickerModal.close();
                    } else {
                        colorPickerModal.show();
                    }
                }
            }
        }
    }

    property bool dockEnabled: false

    Timer {
        id: dockRecreateDebounce
        interval: 500
        repeat: false
        onTriggered: {
            root.dockEnabled = false;
            Qt.callLater(() => {
                root.dockEnabled = true;
            });
        }
    }

    Timer {
        id: loginSoundTimer
        // Half a second delay before playing login sound, otherwise the sound may be cut off
        // 50 is the minimum that seems to work, but 500 is safer
        interval: 500
        repeat: false
        onTriggered: {
            AudioService.playLoginSoundIfApplicable();
        }
    }

    Component.onCompleted: {
        dockRecreateDebounce.start();
        // Force PolkitService singleton to initialize
        PolkitService.polkitAvailable;
        loginSoundTimer.start();
    }

    Loader {
        id: dockLoader
        active: root.dockEnabled
        asynchronous: false

        property var currentPosition: SettingsData.dockPosition
        property bool initialized: false

        sourceComponent: Dock {
            contextMenu: dockContextMenuLoader.item ? dockContextMenuLoader.item : null
        }

        onLoaded: {
            if (item) {
                dockContextMenuLoader.active = true;
            }
        }

        Component.onCompleted: {
            initialized = true;
        }

        onCurrentPositionChanged: {
            if (!initialized)
                return;
            const comp = sourceComponent;
            sourceComponent = null;
            sourceComponent = comp;
        }
    }

    Loader {
        id: dankDashPopoutLoader

        active: false
        asynchronous: false

        Component.onCompleted: {
            PopoutService.dankDashPopoutLoader = dankDashPopoutLoader;
        }

        onLoaded: {
            if (item) {
                PopoutService.dankDashPopout = item;
                PopoutService._onDankDashPopoutLoaded();
            }
        }

        sourceComponent: Component {
            DankDashPopout {
                id: dankDashPopout
                onPopoutClosed: PopoutService.unloadDankDash()
            }
        }
    }

    LazyLoader {
        id: dockContextMenuLoader

        active: false

        DockContextMenu {
            id: dockContextMenu
        }
    }

    LazyLoader {
        id: notificationCenterLoader

        active: false

        Component.onCompleted: {
            PopoutService.notificationCenterLoader = notificationCenterLoader;
        }

        NotificationCenterPopout {
            id: notificationCenter
            onPopoutClosed: PopoutService.unloadNotificationCenter()

            Component.onCompleted: {
                PopoutService.notificationCenterPopout = notificationCenter;
            }
        }
    }

    Variants {
        model: SettingsData.notificationFocusedMonitor ? Quickshell.screens : SettingsData.getFilteredScreens("notifications")

        delegate: NotificationPopupManager {
            modelData: item
        }
    }

    LazyLoader {
        id: controlCenterLoader

        active: false

        property var modalRef: colorPickerModal
        property LazyLoader powerModalLoaderRef: powerMenuModalLoader

        Component.onCompleted: {
            PopoutService.controlCenterLoader = controlCenterLoader;
        }

        ControlCenterPopout {
            id: controlCenterPopout
            colorPickerModal: controlCenterLoader.modalRef
            powerMenuModalLoader: controlCenterLoader.powerModalLoaderRef
            onPopoutClosed: PopoutService.unloadControlCenter()

            onLockRequested: {
                lock.activate();
            }

            Component.onCompleted: {
                PopoutService.controlCenterPopout = controlCenterPopout;
            }
        }
    }

    LazyLoader {
        id: wifiPasswordModalLoader
        active: false

        Component.onCompleted: {
            PopoutService.wifiPasswordModalLoader = wifiPasswordModalLoader;
        }

        WifiPasswordModal {
            id: wifiPasswordModalItem

            Component.onCompleted: {
                PopoutService.wifiPasswordModal = wifiPasswordModalItem;
            }
        }
    }

    LazyLoader {
        id: wifiQRCodeModalLoader
        active: false

        Component.onCompleted: {
            PopoutService.wifiQRCodeModalLoader = wifiQRCodeModalLoader;
        }

        WifiQRCodeModal {
            id: wifiQRCodeModalItem

            Component.onCompleted: {
                PopoutService.wifiQRCodeModal = wifiQRCodeModalItem;
            }
        }
    }

    LazyLoader {
        id: polkitAuthModalLoader
        active: false

        PolkitAuthModal {
            id: polkitAuthModal

            Component.onCompleted: {
                PopoutService.polkitAuthModal = polkitAuthModal;
            }
        }
    }

    Connections {
        target: PolkitService.agent
        enabled: PolkitService.polkitAvailable

        function onAuthenticationRequestStarted() {
            polkitAuthModalLoader.active = true;
            if (polkitAuthModalLoader.item)
                polkitAuthModalLoader.item.show();
        }
    }

    BluetoothPairingModal {
        id: bluetoothPairingModal

        Component.onCompleted: {
            PopoutService.bluetoothPairingModal = bluetoothPairingModal;
        }
    }

    property string lastCredentialsToken: ""
    property var lastCredentialsTime: 0

    Connections {
        target: NetworkService

        function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo) {
            const now = Date.now();
            const timeSinceLastPrompt = now - lastCredentialsTime;

            wifiPasswordModalLoader.active = true;
            if (!wifiPasswordModalLoader.item)
                return;

            if (wifiPasswordModalLoader.item.visible && timeSinceLastPrompt < 1000) {
                NetworkService.cancelCredentials(lastCredentialsToken);
                lastCredentialsToken = token;
                lastCredentialsTime = now;
                wifiPasswordModalLoader.item.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo);
                return;
            }

            lastCredentialsToken = token;
            lastCredentialsTime = now;
            wifiPasswordModalLoader.item.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo);
        }
    }

    LazyLoader {
        id: networkInfoModalLoader

        active: false

        NetworkInfoModal {
            id: networkInfoModal

            Component.onCompleted: {
                PopoutService.networkInfoModal = networkInfoModal;
            }
        }
    }

    LazyLoader {
        id: batteryPopoutLoader

        active: false

        Component.onCompleted: {
            PopoutService.batteryPopoutLoader = batteryPopoutLoader;
        }

        BatteryPopout {
            id: batteryPopout
            onPopoutClosed: PopoutService.unloadBattery()

            Component.onCompleted: {
                PopoutService.batteryPopout = batteryPopout;
            }
        }
    }

    LazyLoader {
        id: layoutPopoutLoader

        active: false

        Component.onCompleted: {
            PopoutService.layoutPopoutLoader = layoutPopoutLoader;
        }

        DWLLayoutPopout {
            id: layoutPopout
            onPopoutClosed: PopoutService.unloadLayoutPopout()

            Component.onCompleted: {
                PopoutService.layoutPopout = layoutPopout;
            }
        }
    }

    LazyLoader {
        id: vpnPopoutLoader

        active: false

        Component.onCompleted: {
            PopoutService.vpnPopoutLoader = vpnPopoutLoader;
        }

        VpnPopout {
            id: vpnPopout
            onPopoutClosed: PopoutService.unloadVpn()

            Component.onCompleted: {
                PopoutService.vpnPopout = vpnPopout;
            }
        }
    }

    LazyLoader {
        id: processListPopoutLoader

        active: false

        Component.onCompleted: {
            PopoutService.processListPopoutLoader = processListPopoutLoader;
        }

        ProcessListPopout {
            id: processListPopout
            onPopoutClosed: PopoutService.unloadProcessListPopout()

            Component.onCompleted: {
                PopoutService.processListPopout = processListPopout;
            }
        }
    }

    LazyLoader {
        id: settingsModalLoader

        active: false

        Component.onCompleted: {
            PopoutService.settingsModalLoader = settingsModalLoader;
        }

        onActiveChanged: {
            if (active && item) {
                PopoutService.settingsModal = item;
                PopoutService._onSettingsModalLoaded();
            }
        }

        SettingsModal {
            id: settingsModal
            property bool wasShown: false

            onVisibleChanged: {
                if (visible) {
                    wasShown = true;
                } else if (wasShown) {
                    PopoutService.unloadSettings();
                }
            }
        }
    }

    LazyLoader {
        id: appDrawerLoader

        active: false

        Component.onCompleted: {
            PopoutService.appDrawerLoader = appDrawerLoader;
        }

        AppDrawerPopout {
            id: appDrawerPopout
            onPopoutClosed: PopoutService.unloadAppDrawer()

            Component.onCompleted: {
                PopoutService.appDrawerPopout = appDrawerPopout;
            }
        }
    }

    LazyLoader {
        id: dankLauncherV2ModalLoader

        active: false

        Component.onCompleted: {
            PopoutService.dankLauncherV2ModalLoader = dankLauncherV2ModalLoader;
        }

        DankLauncherV2Modal {
            id: dankLauncherV2Modal

            Component.onCompleted: {
                PopoutService.dankLauncherV2Modal = dankLauncherV2Modal;
                PopoutService._onDankLauncherV2ModalLoaded();
            }
        }
    }

    LazyLoader {
        id: clipboardHistoryPopoutLoader

        active: false

        Component.onCompleted: {
            PopoutService.clipboardHistoryPopoutLoader = clipboardHistoryPopoutLoader;
        }

        ClipboardHistoryPopout {
            id: clipboardHistoryPopout
            onPopoutClosed: PopoutService.unloadClipboardHistoryPopout()

            Component.onCompleted: {
                PopoutService.clipboardHistoryPopout = clipboardHistoryPopout;
            }
        }
    }

    MuxModal {
        id: muxModal
    }

    ClipboardHistoryModal {
        id: clipboardHistoryModalPopup

        Component.onCompleted: {
            PopoutService.clipboardHistoryModal = clipboardHistoryModalPopup;
        }
    }

    NotificationModal {
        id: notificationModal

        Component.onCompleted: {
            PopoutService.notificationModal = notificationModal;
        }
    }

    BrowserPickerModal {
        id: browserPickerModal
    }

    AppPickerModal {
        id: filePickerModal
        title: I18n.tr("Open with...")
        viewMode: SettingsData.appPickerViewMode || "grid"

        onViewModeChanged: {
            SettingsData.set("appPickerViewMode", viewMode);
        }

        function shellEscape(str) {
            return "'" + str.replace(/'/g, "'\\''") + "'";
        }

        onApplicationSelected: (app, filePath) => {
            if (!app)
                return;
            let cmd = app.exec || "";
            const escapedPath = shellEscape(filePath);
            const escapedUri = shellEscape("file://" + filePath);

            let hasField = false;
            if (cmd.includes("%f")) {
                cmd = cmd.replace("%f", escapedPath);
                hasField = true;
            } else if (cmd.includes("%F")) {
                cmd = cmd.replace("%F", escapedPath);
                hasField = true;
            } else if (cmd.includes("%u")) {
                cmd = cmd.replace("%u", escapedUri);
                hasField = true;
            } else if (cmd.includes("%U")) {
                cmd = cmd.replace("%U", escapedUri);
                hasField = true;
            }

            cmd = cmd.replace(/%[ikc]/g, "");

            if (!hasField) {
                cmd += " " + escapedPath;
            }

            console.log("FilePicker: Launching", cmd);

            Quickshell.execDetached({
                command: ["sh", "-c", cmd]
            });
        }
    }

    Connections {
        target: DMSService
        function onOpenUrlRequested(url) {
            if (url.startsWith("dms://theme/install/")) {
                var themeId = url.replace("dms://theme/install/", "").split(/[?#]/)[0];
                if (themeId) {
                    PopoutService.pendingThemeInstall = themeId;
                    PopoutService.openSettingsWithTab("theme");
                }
                return;
            }
            if (url.startsWith("dms://plugin/install/")) {
                var pluginId = url.replace("dms://plugin/install/", "").split(/[?#]/)[0];
                if (pluginId) {
                    PopoutService.pendingPluginInstall = pluginId;
                    PopoutService.openSettingsWithTab("plugins");
                }
                return;
            }
            browserPickerModal.url = url;
            browserPickerModal.open();
        }

        function onAppPickerRequested(data) {
            console.log("DMSShell: App picker requested with data:", JSON.stringify(data));

            if (!data || !data.target) {
                console.warn("DMSShell: Invalid app picker request data");
                return;
            }

            filePickerModal.targetData = data.target;
            filePickerModal.targetDataLabel = data.requestType || "file";

            if (data.categories && data.categories.length > 0) {
                filePickerModal.categoryFilter = data.categories;
            } else {
                filePickerModal.categoryFilter = [];
            }

            filePickerModal.usageHistoryKey = "filePickerUsageHistory";
            filePickerModal.open();
        }
    }

    DankColorPickerModal {
        id: colorPickerModal

        Component.onCompleted: {
            PopoutService.colorPickerModal = colorPickerModal;
        }
    }

    LazyLoader {
        id: workspaceRenameModalLoader

        active: false

        Component.onCompleted: PopoutService.workspaceRenameModalLoader = workspaceRenameModalLoader

        WorkspaceRenameModal {
            id: workspaceRenameModal
        }
    }

    LazyLoader {
        id: windowRuleModalLoader

        active: false

        Component.onCompleted: PopoutService.windowRuleModalLoader = windowRuleModalLoader

        WindowRuleModal {
            id: windowRuleModal
        }
    }

    LazyLoader {
        id: processListModalLoader

        active: false

        Component.onCompleted: PopoutService.processListModalLoader = processListModalLoader

        ProcessListModal {
            id: processListModal

            Component.onCompleted: {
                PopoutService.processListModal = processListModal;
            }
        }
    }

    LazyLoader {
        id: systemUpdateLoader

        active: false

        Component.onCompleted: {
            PopoutService.systemUpdateLoader = systemUpdateLoader;
        }

        SystemUpdatePopout {
            id: systemUpdatePopout
            onPopoutClosed: PopoutService.unloadSystemUpdate()

            Component.onCompleted: {
                PopoutService.systemUpdatePopout = systemUpdatePopout;
            }
        }
    }

    Variants {
        id: notepadSlideoutVariants
        model: SettingsData.getFilteredScreens("notepad")

        delegate: DankSlideout {
            id: notepadSlideout
            modelData: item
            title: I18n.tr("Notepad")
            slideoutWidth: 480
            expandable: true
            expandedWidthValue: 960
            customTransparency: SettingsData.notepadTransparencyOverride

            content: Component {
                Notepad {
                    slideout: notepadSlideout
                    onHideRequested: notepadSlideout.hide()
                }
            }

            function toggle() {
                if (isVisible) {
                    hide();
                } else {
                    show();
                }
            }
        }

        onInstancesChanged: PopoutService.notepadSlideouts = instances
        Component.onCompleted: PopoutService.notepadSlideouts = instances
    }

    LazyLoader {
        id: powerMenuModalLoader

        active: false

        PowerMenuModal {
            id: powerMenuModal

            onPowerActionRequested: (action, title, message) => {
                switch (action) {
                case "logout":
                    SessionService.logout();
                    break;
                case "suspend":
                    SessionService.suspend();
                    break;
                case "hibernate":
                    SessionService.hibernate();
                    break;
                case "reboot":
                    SessionService.reboot();
                    break;
                case "poweroff":
                    SessionService.poweroff();
                    break;
                }
            }

            onLockRequested: {
                lock.activate();
            }

            Component.onCompleted: {
                PopoutService.powerMenuModal = powerMenuModal;
            }
        }
    }

    LazyLoader {
        id: hyprKeybindsModalLoader

        active: false

        KeybindsModal {
            id: keybindsModal

            Component.onCompleted: {
                PopoutService.hyprKeybindsModal = keybindsModal;
            }
        }
    }

    DMSShellIPC {
        powerMenuModalLoader: powerMenuModalLoader
        processListModalLoader: processListModalLoader
        controlCenterLoader: controlCenterLoader
        dankDashPopoutLoader: dankDashPopoutLoader
        notepadSlideoutVariants: notepadSlideoutVariants
        hyprKeybindsModalLoader: hyprKeybindsModalLoader
        dankBarRepeater: dankBarRepeater
        hyprlandOverviewLoader: hyprlandOverviewLoader
        workspaceRenameModalLoader: workspaceRenameModalLoader
        windowRuleModalLoader: windowRuleModalLoader
    }

    Variants {
        model: SettingsData.getFilteredScreens("toast")

        delegate: Toast {
            modelData: item
            visible: ToastService.toastVisible
        }
    }

    Variants {
        model: SettingsData.getFilteredScreens("osd")

        delegate: VolumeOSD {
            modelData: item
        }
    }

    Variants {
        model: SettingsData.getFilteredScreens("osd")

        delegate: MediaVolumeOSD {
            modelData: item
        }
    }

    Variants {
        model: SettingsData.getFilteredScreens("osd")

        delegate: MediaPlaybackOSD {
            modelData: item
        }
    }

    Variants {
        model: SettingsData.getFilteredScreens("osd")

        delegate: MicMuteOSD {
            modelData: item
        }
    }

    Variants {
        model: SettingsData.getFilteredScreens("osd")

        delegate: BrightnessOSD {
            modelData: item
        }
    }

    Variants {
        model: SettingsData.getFilteredScreens("osd")

        delegate: IdleInhibitorOSD {
            modelData: item
        }
    }

    Loader {
        id: powerProfileWatcherLoader
        active: SettingsData.osdPowerProfileEnabled
        source: "Services/PowerProfileWatcher.qml"
    }

    Variants {
        model: SettingsData.osdPowerProfileEnabled ? SettingsData.getFilteredScreens("osd") : []

        delegate: PowerProfileOSD {
            modelData: item
        }
    }

    Variants {
        model: SettingsData.getFilteredScreens("osd")

        delegate: CapsLockOSD {
            modelData: item
        }
    }

    Variants {
        model: SettingsData.getFilteredScreens("osd")

        delegate: AudioOutputOSD {
            modelData: item
        }
    }

    LazyLoader {
        id: hyprlandOverviewLoader
        active: CompositorService.isHyprland
        component: HyprlandOverview {
            id: hyprlandOverview
        }
    }

    LazyLoader {
        id: niriOverviewOverlayLoader
        active: CompositorService.isNiri && SettingsData.niriOverviewOverlayEnabled
        component: NiriOverviewOverlay {
            id: niriOverviewOverlay
        }
    }

    Loader {
        id: greeterLoader
        active: false
        sourceComponent: GreeterModal {
            onGreeterCompleted: greeterLoader.active = false
            Component.onCompleted: show()
        }

        Connections {
            target: FirstLaunchService
            function onGreeterRequested() {
                if (greeterLoader.active && greeterLoader.item) {
                    greeterLoader.item.show();
                    return;
                }
                greeterLoader.active = true;
            }
        }
    }

    Loader {
        id: changelogLoader
        active: false
        sourceComponent: ChangelogModal {
            onChangelogDismissed: changelogLoader.active = false
            Component.onCompleted: show()
        }

        Connections {
            target: ChangelogService
            function onChangelogRequested() {
                if (changelogLoader.active && changelogLoader.item) {
                    changelogLoader.item.show();
                    return;
                }
                changelogLoader.active = true;
            }
        }
    }
}
