import QtQuick
import Quickshell
import Quickshell.Widgets
import "../.."

Item {
    id: root
    width: parent ? parent.width : 1280
    height: parent ? parent.height : 820
    focus: true

    /* ------------------------------
       PIXEL CONSTANTS (DO NOT TOUCH)
       ------------------------------ */

    property int menuLeft: 64
    property int menuTop: 140
    property int lineHeight: 38 + 40 + 1

    property int nameFontSize: 32
    property int stateFontSize: 28

    property int stateColumnX: 824

    property int soulOffsetX: -36 - 32
    property int soulOffsetY: -26

    /* ------------------------------ */

    property int iconSize: 36
    property int textStartX: 239
    property int textRightPadding: 96
    property int visibleRows: Math.max(1, Math.floor((height - menuTop - 64) / lineHeight))
    property int scrollOffset: 0

    property ShellStateManager manager: null
    property int activeSelection: 0
    property bool isSelected: true

    ListModel {
        id: appEntriesModel
    }

    function clamp(v, lo, hi) {
        return Math.max(lo, Math.min(hi, v));
    }

    function menuLength() {
        return appEntriesModel.count;
    }

    function menuAt(index) {
        if (index < 0 || index >= appEntriesModel.count)
            return null;
        var row = appEntriesModel.get(index);
        return row ? row.entry : null;
    }

    function wrapIndex(i) {
        const length = menuLength();
        if (length === 0)
            return 0;
        return (i + length) % length;
    }

    function clampSelection() {
        const length = menuLength();
        if (length === 0) {
            activeSelection = 0;
            return;
        }
        activeSelection = clamp(activeSelection, 0, length - 1);
    }

    function ensureVisible() {
        const length = menuLength();
        if (length === 0)
            return;
        if (activeSelection < scrollOffset)
            scrollOffset = activeSelection;
        else if (activeSelection >= scrollOffset + visibleRows)
            scrollOffset = Math.max(0, activeSelection - visibleRows + 1);
    }

    function appName(entry) {
        if (!entry)
            return "";
        if (entry.name && entry.name.length > 0)
            return entry.name;
        return entry.id || "";
    }

    function appUsageCount(entry) {
        if (!entry || !manager || !manager.appUsageCounts)
            return 0;
        var key = entry.id || entry.name;
        return manager.appUsageCounts[key] || 0;
    }

    function applicationsToArray() {
        var apps = DesktopEntries.applications;
        var list = [];
        if (!apps)
            return list;
        if (apps.values && apps.values.length !== undefined) {
            for (var i = 0; i < apps.values.length; i++) {
                list.push(apps.values[i]);
            }
        } else if (apps.length !== undefined) {
            for (var j = 0; j < apps.length; j++) {
                list.push(apps[j]);
            }
        } else if (apps.count !== undefined && apps.get) {
            for (var k = 0; k < apps.count; k++) {
                list.push(apps.get(k));
            }
        }
        return list;
    }

    function rebuildAppEntries() {
        var list = applicationsToArray();
        console.log("AppLauncher: rebuilding entries", list.length);
        var filtered = [];
        for (var i = 0; i < list.length; i++) {
            var entry = list[i];
            if (!entry)
                continue;
            if (entry.noDisplay)
                continue;
            filtered.push(entry);
        }
        console.log("AppLauncher: filtered entries", filtered.length);
        filtered.sort(function (a, b) {
            var usageA = appUsageCount(a);
            var usageB = appUsageCount(b);
            if (usageA !== usageB)
                return usageB - usageA;
            var nameA = appName(a);
            var nameB = appName(b);
            return nameA.localeCompare(nameB);
        });
        appEntriesModel.clear();
        for (var i = 0; i < filtered.length; i++) {
            appEntriesModel.append({
                entry: filtered[i]
            });
        }
        clampSelection();
        ensureVisible();
    }

    Connections {
        target: DesktopEntries
        function onApplicationsChanged() {
            rebuildAppEntries();
        }
    }

    Connections {
        target: manager
        ignoreUnknownSignals: true
        function onAppUsageCountsChanged() {
            rebuildAppEntries();
        }
        function onAppLauncherOpened() {
            activeSelection = 0;
            isSelected = true;
            clampSelection();
        }
    }

    Text {
        text: "APPS"
        font.family: "8bitoperator JVE"
        font.pixelSize: 71
        renderType: Text.NativeRendering
        font.hintingPreference: Font.PreferNoHinting
        smooth: false
        antialiasing: false
        anchors.horizontalCenter: parent.horizontalCenter
        color: "#ffffff"
        y: 32
    }

    Repeater {
        model: appEntriesModel

        delegate: Item {
            width: root.width
            height: lineHeight
            x: 0
            y: menuTop + (index - root.scrollOffset) * lineHeight
            visible: index >= root.scrollOffset && index < root.scrollOffset + root.visibleRows

            Text {
                x: root.textStartX
                y: 0
                text: root.appName(model.entry)
                width: root.width - root.textStartX - root.textRightPadding
                font.family: "8bitoperator JVE"
                font.pixelSize: 71
                font.letterSpacing: 1
                renderType: Text.NativeRendering
                font.hintingPreference: Font.PreferNoHinting
                smooth: false
                antialiasing: false
                wrapMode: Text.NoWrap
                elide: Text.ElideRight
                color: (root.activeSelection == index && root.isSelected == true) ? "#fefe00" : "#ffffff"
            }

            IconImage {
                id: appIcon
                x: 182
                y: 8 + 14
                implicitSize: root.iconSize
                source: Quickshell.iconPath(model.entry && model.entry.icon ? model.entry.icon : "")
                asynchronous: true
            }

            Image {
                source: "../QuickSettings/soul.png"
                width: 36
                height: 36
                x: appIcon.x
                y: appIcon.y
                opacity: 0.7
                visible: root.activeSelection == index
            }
        }
    }

    /* ------------------------------
       INPUT HANDLING
       ------------------------------ */

    function handleKey(key) {
        switch (key) {
        case Qt.Key_Up:
            activeSelection = wrapIndex(activeSelection - 1);
            ensureVisible();
            return true;
        case Qt.Key_Down:
            activeSelection = wrapIndex(activeSelection + 1);
            ensureVisible();
            return true;
        case Qt.Key_Z:
        case Qt.Key_Return:
        case Qt.Key_Enter:
            {
                var entry = menuAt(activeSelection);
                if (entry) {
                    if (manager && manager.bumpAppUsage) {
                        manager.bumpAppUsage(entry.id || entry.name);
                    }
                    entry.execute();
                }
                if (manager && manager.closeShell) {
                    manager.closeShell();
                }
                return true;
            }
        case Qt.Key_X:
        case Qt.Key_Shift:
        case Qt.Key_Escape:
            if (manager && manager.closeAppLauncher) {
                manager.closeAppLauncher();
            }
            return true;
        }
        return false;
    }

    Component.onCompleted: {
        activeSelection = 0;
        isSelected = true;
        scrollOffset = 0;
        rebuildAppEntries();
        Qt.callLater(rebuildAppEntries);
        ShellInputManager.registerHandler("appLauncher", handleKey);
    }

    Component.onDestruction: {
        ShellInputManager.unregisterHandler("appLauncher");
    }
}
