import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import Quickshell.Io
import Quickshell.Hyprland

import "../config" as Cfg

PanelWindow {
    id: root

    property bool isTop:     true
    property int  barHeight: Cfg.Config.barHeight
    property int  barMargin: Cfg.Config.margin

    readonly property var t: Cfg.Config.theme

    readonly property int launcherGap: 12

    GlobalShortcut {
        id: launcherShortcut
        name: "toggle"
        onPressed: root.toggle()
    }

    property bool   _isOpen:      false
    readonly property bool isOpen: _isOpen
    property string mode:         "drun"
    property bool   _keyboardNav: false
    property var    allItems:     []
    property bool   loading:      false
    property bool   proxyMode:    false

    // When launcherSelectFirst is true the first result is pre-selected;
    // otherwise the list starts with no selection (-1).
    readonly property int defaultIndex: Cfg.Config.launcherSelectFirst ? 0 : -1

    readonly property var filteredItems: {
        const q = searchInput.text.toLowerCase()
        if (!q) return allItems.slice(0, 80)
        return allItems.filter(i => i.name.toLowerCase().includes(q))
    }

    function toggle() { _isOpen ? close() : open() }

    function open() {
        closeTimer.stop()
        visible = true
        _isOpen = true
        searchInput.text = ""
        resultsList.currentIndex = root.defaultIndex
        loadItems()
        Qt.callLater(() => searchInput.forceActiveFocus())
    }

    function close() {
        _isOpen = false
        closeTimer.restart()
    }

    Connections {
        target: root
        function onActiveChanged() {
            if (!root.active && root._isOpen) root.close()
        }
    }

    function loadItems() {
        loading = true
        readCache()
        updateProc.command = [Cfg.Config.launcherScript, "--update-only"]
        updateProc.running = true
    }

    function readCache() {
        const path = Cfg.Config.launcherCacheDir + "/" + (mode === "drun" ? "drun.txt" : "run.txt")
        dataProc.rawOutput = ""
        dataProc.command   = ["bash", "-c", "cat " + path]
        dataProc.running   = true
    }

    function launch(item) {
        if (!item || !item.exec) return

        const cleanExec = item.exec.replace(/%[fFuUik]/g, "").trim()
        const finalExec = root.proxyMode ? "proxychains4 " + cleanExec : cleanExec
        const logPath   = "/tmp/qml_launch.log"

        launchProc.command = ["sh", "-c", finalExec + " > " + logPath + " 2>&1 &"]
        launchProc.running = true

        console.log("Launching: " + finalExec)
        if (typeof close === "function") close()
    }

    onModeChanged: if (_isOpen) loadItems()

    visible: false
    color:   "transparent"
   
    anchors { top: true; bottom: true; left: true; right: true }
    WlrLayershell.layer:         WlrLayer.Overlay
    WlrLayershell.namespace:     "main-shell-launcher"
    WlrLayershell.exclusiveZone: -1
    WlrLayershell.keyboardFocus: _isOpen ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
    mask: Region { item: (root._isOpen && Cfg.Config.launcherCloseOnClickOutside) ? fullMask : clipContainer }

    // Full-screen item used as input mask when click-outside-to-close is enabled.
    // Lets the background MouseArea receive events outside the bubble.
    Item { id: fullMask; anchors.fill: parent }

    Timer {
        id: closeTimer
        interval: Cfg.Config.popupAnimDuration + 70
        onTriggered: {
            root.visible  = false
            root.mode     = "drun"
            root.allItems = []
        }
    }

    Process {
        id: updateProc
        onRunningChanged: if (!running) root.readCache()
    }

    Process {
        id: dataProc
        property string rawOutput: ""
        stdout: SplitParser { onRead: data => dataProc.rawOutput += data + "\n" }
        onRunningChanged: {
            if (!running && rawOutput) {
                const lines = rawOutput.trim().split("\n")
                const items = []
                for (let i = 0; i < lines.length; i++) {
                    const p = lines[i].split("\t")
                    if (p.length >= 3) items.push({ name: p[0], exec: p[1], id: p[2], icon: p[3] || "" })
                }
                root.allItems = items
                root.loading  = false
            }
        }
    }

    Process { id: launchProc }

    // Transparent overlay — captures clicks outside the bubble and closes the
    // launcher. Sits below clipContainer in stacking order (declared first),
    // so clicks inside the bubble still reach the bubble's own MouseAreas.
    MouseArea {
        anchors.fill: parent
        enabled: root._isOpen && Cfg.Config.launcherCloseOnClickOutside
        onClicked: root.close()
    }

    Item {
        id: clipContainer
        anchors.horizontalCenter: parent.horizontalCenter
        width: 460

        anchors.top:          root.isTop ? parent.top    : undefined
        anchors.bottom:       root.isTop ? undefined     : parent.bottom
        anchors.topMargin:    root.isTop ? (root.barHeight + root.launcherGap) : 0
        anchors.bottomMargin: root.isTop ? 0 : (root.barHeight + root.launcherGap)
        height: parent.height - root.barHeight - root.launcherGap

        clip: true 

        Rectangle {
            id: bubble
            width: parent.width
            property int targetHeight: Math.min(layout.implicitHeight + 28, 540)
            height: targetHeight

            anchors.top:    root.isTop ? parent.top    : undefined
            anchors.bottom: root.isTop ? undefined     : parent.bottom

            transform: Translate {
                y: root._isOpen ? 0 : (root.isTop ? -bubble.height : bubble.height)
                
                Behavior on y {
                    NumberAnimation { 
                        duration: Cfg.Config.popupAnimDuration; 
                        easing.type: Easing.OutExpo 
                    }
                    enabled: root.visible
                }
            }

            opacity: root._isOpen ? 1 : 0
            Behavior on opacity { NumberAnimation { duration: 200 } }

            radius:       Cfg.Config.popupRadius
            color:        t.launcherBg
            border.color: t.launcherBorder
            border.width: Cfg.Config.popupBorderWidth

            focus: root._isOpen
            Keys.onEscapePressed: root.close()

            ColumnLayout {
                id: layout
                anchors.fill: parent
                anchors.margins: 14
                spacing: 10

                // ── Search input ──────────────────────────────────────────
                Rectangle {
                    Layout.fillWidth: true
                    height: 44
                    radius: 10
                    color: t.launcherInput
                    border.color: searchInput.activeFocus ? t.launcherInputBorderFocus : t.launcherBorder
                    border.width: Cfg.Config.popupBorderWidth

                    Behavior on color { NumberAnimation { duration: 180 } }

                    RowLayout {
                        anchors.fill: parent
                        anchors.leftMargin:  12
                        anchors.rightMargin: 8
                        spacing: 10

                        TextInput {
                            id: searchInput
                            Layout.fillWidth: true
                            color: t.launcherText
                            font.pixelSize: 15
                            verticalAlignment: TextInput.AlignVCenter
                            selectionColor: t.launcherAccent

                            onTextChanged: resultsList.currentIndex = root.defaultIndex

                            Keys.onReturnPressed: {
                                if (root.filteredItems.length > 0) {
                                    let idx = resultsList.currentIndex;
                                    if (idx === -1) idx = 0;
                                    root.launch(root.filteredItems[idx]);
                                }
                            }

                            Keys.onDownPressed: {
                                root._keyboardNav = true
                                if (resultsList.currentIndex < 0) {
                                    resultsList.currentIndex = 0;
                                } else {
                                    resultsList.currentIndex = Math.min(resultsList.currentIndex + 1, resultsList.count - 1)
                                }
                                resultsList.positionViewAtIndex(resultsList.currentIndex, ListView.Contain)
                            }

                            Keys.onUpPressed: {
                                root._keyboardNav = true
                                if (resultsList.currentIndex < 0) {
                                    resultsList.currentIndex = resultsList.count - 1;
                                } else {
                                    resultsList.currentIndex = Math.max(resultsList.currentIndex - 1, 0)
                                }
                                resultsList.positionViewAtIndex(resultsList.currentIndex, ListView.Contain)
                            }
                            
                            Keys.onTabPressed: root.mode = root.mode === "drun" ? "run" : "drun"
                        }

                        Rectangle {
                            height: 28
                            width:  modeRow.implicitWidth + 10
                            radius: 8
                            color:        t.launcherPill
                            border.color: t.launcherBorder
                            border.width: Cfg.Config.popupBorderWidth

                            RowLayout {
                                id: modeRow
                                anchors.centerIn: parent
                                spacing: 2
                                Repeater {
                                    model: ["drun", "run"]
                                    delegate: Rectangle {
                                        height: 22
                                        width:  label.implicitWidth + 14
                                        radius: 6
                                        color: root.mode === modelData ? t.launcherModeActiveBg : "transparent"
                                        Text {
                                            id: label
                                            anchors.centerIn: parent
                                            text: modelData
                                            font.pixelSize: 10
                                            font.bold: root.mode === modelData
                                            color: root.mode === modelData ? t.launcherModeActiveText : t.launcherDim
                                        }
                                        MouseArea {
                                            anchors.fill: parent
                                            onClicked: root.mode = modelData
                                        }
                                    }
                                }
                            }
                        }

                        // ── Proxychains toggle ────────────────────────────
                        Rectangle {
                            id: proxyBtn
                            height: 28
                            width: 110 
                            radius: 8
                            color:        root.proxyMode ? Qt.rgba(1, 0.35, 0.35, 0.22) : t.launcherPill
                            border.color: root.proxyMode ? Qt.rgba(1, 0.35, 0.35, 0.65) : t.launcherBorder
                            border.width: Cfg.Config.popupBorderWidth
                            Behavior on color        { ColorAnimation { duration: 150 } }
                            Behavior on border.color { ColorAnimation { duration: 150 } }

                            RowLayout {
                                id: proxyBtnRow
                                anchors.centerIn: parent
                                spacing: 5
                                Text {
                                    text:           "󰒃"
                                    font.pixelSize: 11
                                    color:          root.proxyMode ? Qt.rgba(1, 0.45, 0.45, 1) : t.launcherDim
                                    Behavior on color { ColorAnimation { duration: 150 } }
                                }
                                Text {
                                    text:           "proxychains4"
                                    font.pixelSize: 10
                                    font.bold:      root.proxyMode
                                    color:          root.proxyMode ? Qt.rgba(1, 0.45, 0.45, 1) : t.launcherDim
                                    Behavior on color { ColorAnimation { duration: 150 } }
                                }
                            }

                            MouseArea {
                                anchors.fill: parent
                                cursorShape:  Qt.PointingHandCursor
                                onClicked:    root.proxyMode = !root.proxyMode
                            }
                        }
                    }
                }

                ListView {
                    id: resultsList
                    Layout.fillWidth: true
                    implicitHeight: Math.min(contentHeight, 400)
                    clip: true
                    model: root.filteredItems
                    currentIndex: root.defaultIndex
                    spacing: 2

                    onModelChanged: currentIndex = root.defaultIndex
                    ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }

                    delegate: Rectangle {
                        width: resultsList.width
                        height: 38
                        radius: 8
                        property bool hovered: false

                        color: hovered ? t.launcherHover
                            : (resultsList.currentIndex === index && index !== -1
                                ? t.launcherSelected : "transparent")

                        RowLayout {
                            anchors.fill: parent
                            anchors.leftMargin:  12
                            anchors.rightMargin: 12
                            spacing: 12

                            Item {
                                width: 22; height: 22
                                Layout.alignment: Qt.AlignVCenter

                                Image {
                                    id: appIcon
                                    anchors.fill: parent
                                    source:       modelData.icon ? "image://icon/" + modelData.icon : ""
                                    fillMode:     Image.PreserveAspectFit
                                    smooth:       true
                                    visible:      status === Image.Ready
                                }

                                Text {
                                    anchors.centerIn: parent
                                    visible:        !appIcon.visible
                                    text:           root.mode === "drun" ? "󰣆" : "󰆍"
                                    color:          resultsList.currentIndex === index && index !== -1 ? t.launcherAccent : t.launcherDim
                                    font.pixelSize: 16
                                }
                            }

                            Text {
                                text: modelData.name
                                color: t.launcherText
                                font.pixelSize: 14
                                Layout.fillWidth: true
                                elide: Text.ElideRight
                            }
                        }

                        MouseArea {
                            anchors.fill: parent
                            hoverEnabled: true
                            onEntered: parent.hovered = true
                            onExited:  parent.hovered = false
                            onClicked: root.launch(modelData)
                        }
                    }
                }
            }
        }
    }
}
