import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.config
import qs.modules.functions
import qs.modules.components
import qs.services

/* 

This LauncherContent has been depricated.
And yet not used. (4/3/26)

*/

Item {
    id: content

    property int selectedIndex: -1
    property string searchQuery: ""
    property var calcVars: ({})

    property alias listView: listView
    property alias filteredModel: filteredModel

    function launchCurrent() {
        launchApp(listView.currentIndex)
    }

    function webSearchUrl(query) {
        const engine = (Config.runtime.launcher.webSearchEngine || "").toLowerCase()
        if (engine.startsWith("http"))
            return engine.replace("%s", encodeURIComponent(query))

        const engines = {
            "google": "https://www.google.com/search?q=%s",
            "duckduckgo": "https://duckduckgo.com/?q=%s",
            "brave": "https://search.brave.com/search?q=%s",
            "bing": "https://www.bing.com/search?q=%s",
            "startpage": "https://www.startpage.com/search?q=%s"
        }
        const template = engines[engine] || engines["duckduckgo"]
        return template.replace("%s", encodeURIComponent(query))
    }

    function moveSelection(delta) {
        if (filteredModel.count === 0) return

        selectedIndex = Math.max(0, Math.min(selectedIndex + delta, filteredModel.count - 1))
        listView.currentIndex = selectedIndex
        listView.positionViewAtIndex(selectedIndex, ListView.Contain)
    }

    function fuzzyMatch(text, pattern) {
        text = text.toLowerCase()
        pattern = pattern.toLowerCase()
        let ti = 0, pi = 0
        while (ti < text.length && pi < pattern.length) {
            if (text[ti] === pattern[pi]) pi++
            ti++
        }
        return pi === pattern.length
    }

    function evalExpression(expr) {
        try {
            const fn = new Function("vars", `
                with (vars) { with (Math) { return (${expr}); } }
            `)
            const res = fn(calcVars)
            if (res === undefined || Number.isNaN(res)) return null
            return res
        } catch (e) {
            return null
        }
    }

    function updateFilter() {
        filteredModel.clear()
        const query = searchQuery.toLowerCase().trim()

        const calcVal = evalExpression(query)
        if (calcVal !== null && query !== "") {
            filteredModel.append({
                name: String(calcVal),
                displayName: String(calcVal),
                comment: "Calculation",
                icon: "",
                exec: "",
                isCalc: true,
                isWeb: false
            })
        }

        const sourceApps = AppRegistry.apps

        if (query === "") {
            for (let app of sourceApps) {
                filteredModel.append({
                    name: app.name,
                    displayName: app.name,
                    comment: app.comment,
                    icon: AppRegistry.iconForDesktopIcon(app.icon),
                    exec: app.exec,
                    isCalc: false,
                    isWeb: false
                })
            }
            selectedIndex = filteredModel.count > 0 ? 0 : -1
            listView.currentIndex = selectedIndex
            return
        }

        let exactMatches = []
        let startsWithMatches = []
        let containsMatches = []
        let fuzzyMatches = []

        for (let app of sourceApps) {
            const name = app.name ? app.name.toLowerCase() : ""
            const comment = app.comment ? app.comment.toLowerCase() : ""

            if (name === query) exactMatches.push(app)
            else if (name.startsWith(query)) startsWithMatches.push(app)
            else if (name.includes(query) || comment.includes(query)) containsMatches.push(app)
            else if (Config.runtime.launcher.fuzzySearchEnabled && fuzzyMatch(name, query)) fuzzyMatches.push(app)
        }

        const sortedResults = [
            ...exactMatches,
            ...startsWithMatches,
            ...containsMatches,
            ...fuzzyMatches
        ]

        for (let app of sortedResults) {
            filteredModel.append({
                name: app.name,
                displayName: app.name,
                comment: app.comment,
                icon: AppRegistry.iconForDesktopIcon(app.icon),
                exec: app.exec,
                isCalc: false,
                isWeb: false
            })
        }

        if (filteredModel.count === 0 && query !== "") {
            filteredModel.append({
                name: query,
                displayName: "Search the web for \"" + query + "\"",
                comment: "Web search",
                icon: "public",
                exec: webSearchUrl(query),
                isCalc: false,
                isWeb: true
            })
        }

        selectedIndex = filteredModel.count > 0 ? 0 : -1
        listView.currentIndex = selectedIndex
        listView.positionViewAtBeginning()
    }

    function launchApp(idx) {
        if (idx < 0 || idx >= filteredModel.count) return

        const app = filteredModel.get(idx)
        if (app.isCalc) return
        if (app.isWeb)
            Quickshell.execDetached(["xdg-open", app.exec])
        else
            Quickshell.execDetached(["bash", "-c", app.exec + " &"])

        closeLauncher()
    }

    function closeLauncher() {
        Globals.visiblility.launcher = false
    }

    function resetSearch() {
        searchQuery = ""
        updateFilter()
        selectedIndex = -1
        listView.currentIndex = -1
    }

    Connections {
        target: AppRegistry
        function onReady() {
            updateFilter()
        }
    }

    anchors.fill: parent
    opacity: Globals.visiblility.launcher ? 1 : 0
    anchors.margins: Metrics.margin(10)

    ListModel { id: filteredModel }

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: Metrics.margin(16)
        spacing: Metrics.spacing(12)

        ScrollView {
            Layout.fillWidth: true
            Layout.fillHeight: true
            clip: true

            ListView {
                id: listView
                model: filteredModel
                spacing: Metrics.spacing(8)
                clip: true
                boundsBehavior: Flickable.StopAtBounds
                highlightRangeMode: ListView.StrictlyEnforceRange
                preferredHighlightBegin: 0
                preferredHighlightEnd: height
                highlightMoveDuration: 120
                currentIndex: selectedIndex

                delegate: Rectangle {
                    property bool isSelected: listView.currentIndex === index

                    width: listView.width
                    height: 60
                    radius: Appearance.rounding.normal
                    color: isSelected ? Appearance.m3colors.m3surfaceContainerHighest : "transparent"

                    Row {
                        anchors.fill: parent
                        anchors.margins: Metrics.margin(10)
                        spacing: Metrics.spacing(12)

                        Item {
                            width: 32
                            height: 32

                            Image {
                                anchors.fill: parent
                                visible: !model.isCalc && !model.isWeb
                                smooth: true
                                mipmap: true
                                antialiasing: true
                                fillMode: Image.PreserveAspectFit
                                sourceSize.width: 128
                                sourceSize.height: 128
                                source: model.icon
                            }

                            MaterialSymbol {
                                anchors.centerIn: parent
                                visible: model.isCalc
                                icon: "calculate"
                                iconSize: Metrics.iconSize(28)
                                color: Appearance.m3colors.m3onSurfaceVariant
                            }

                            MaterialSymbol {
                                anchors.centerIn: parent
                                visible: model.isWeb
                                icon: "public"
                                iconSize: Metrics.iconSize(28)
                                color: Appearance.m3colors.m3onSurfaceVariant
                            }
                        }

                        Column {
                            anchors.verticalCenter: parent.verticalCenter
                            width: listView.width - 120
                            spacing: Metrics.spacing(4)

                            Text {
                                text: model.displayName
                                font.pixelSize: Metrics.fontSize(14)
                                font.bold: true
                                elide: Text.ElideRight
                                color: Appearance.m3colors.m3onSurface
                            }

                            Text {
                                text: model.comment
                                font.pixelSize: Metrics.fontSize(11)
                                elide: Text.ElideRight
                                color: Appearance.m3colors.m3onSurfaceVariant
                            }
                        }
                    }

                    MouseArea {
                        anchors.fill: parent
                        hoverEnabled: true
                        cursorShape: Qt.PointingHandCursor
                        onClicked: launchApp(index)
                        onEntered: listView.currentIndex = index
                    }
                }
            }
        }
    }

    Behavior on opacity {
        enabled: Config.runtime.appearance.animations.enabled
        NumberAnimation {
            duration: Metrics.chronoDuration(400)
            easing.type: Easing.BezierSpline
            easing.bezierCurve: Appearance.animation.curves.standard
        }
    }
}
