(function ($, w, d) {
    w.clientexec = w.clientexec || {};
    w.clientexec.globalSearch = w.clientexec.globalSearch || {};

    let resultsBox, searchInput, clearButton;
    let searchTimeout = null;
    let currentQuery = "";

    // Optional: purely visual mapping. If a new type appears, it will still render (fallback icon/style).
    const typeStyleMap = {
        Client: { iconText: (item) => (item.name ? item.name.trim().charAt(0).toUpperCase() : "C"), iconClass: "icon-client" },
        Package: { iconText: () => "P", iconClass: "icon-package" },
        Domain: { iconText: () => "D", iconClass: "icon-package" },
        Ticket: { iconText: () => "#", iconClass: "icon-ticket" },
        Invoice: { iconText: () => "$", iconClass: "icon-invoice" }
    };

    $(function () {
        resultsBox = d.getElementById("search-results");
        searchInput = d.getElementById("searchInput");
        clearButton = d.getElementById("clear-search");

        if (!resultsBox || !searchInput) return;

        $("#searchInput").on("input", function () {
            w.clientexec.globalSearch.search(this.value);
        });

        $("#clear-search").on("click", function (e) {
            e.preventDefault();
            w.clientexec.globalSearch.clearSearch();
        });
    });

    w.clientexec.globalSearch.search = function (value) {
        clearTimeout(searchTimeout);
        currentQuery = (value || "").trim();

        if (!currentQuery) {
            w.clientexec.globalSearch.clearSearch();
            return;
        }

        if (clearButton) clearButton.style.display = "block";

        searchTimeout = setTimeout(() => {
            $.ajax({
                url: "index.php?fuse=admin&action=getsearchresults",
                data: { query: currentQuery, limit: -1 },
                dataType: "json",
                success: function (response) {
                    if (!response || !response.success || !Array.isArray(response.matches)) {
                        renderEmpty();
                        return;
                    }

                    // Group by API-provided "type" (e.g., "Client", "Package", ...)
                    const grouped = {};
                    response.matches.forEach(m => {
                        if (!m || !m.type) return;
                        if (!grouped[m.type]) grouped[m.type] = [];
                        grouped[m.type].push(m);
                    });

                    renderResults(grouped);
                },
                error: function () {
                    renderError();
                }
            });
        }, 300);
    };

    function renderResults(grouped) {
        const groupTypes = Object.keys(grouped);
        if (groupTypes.length === 0) {
            renderEmpty();
            return;
        }

        // Keep a stable order using the order matches arrived in:
        // (Object.keys preserves insertion order for string keys in modern JS engines)
        let html = `<div class="search-results-inner">`;

        groupTypes.forEach(type => {
            const items = grouped[type] || [];
            if (items.length === 0) return; // only show groups with matches

            const label = String(type).toUpperCase();
            const countText = `${items.length} result${items.length !== 1 ? "s" : ""}`;

            html += `
                <div class="results-header" data-target="${escapeAttr(type)}">
                    <div class="header-left">
                        <span class="chevron collapsed" id="${escapeAttr(type)}-chevron"></span>
                        <span>${label}</span>
                    </div>
                    <span class="collapsed-note">${countText}</span>
                </div>
                <div class="results-group d-none" id="${escapeAttr(type)}">
            `;

            items.forEach(item => {
                const safeUrl = item.url || "#";
                const title = item.name || "";
                const extra = item.extra || "";
                const tooltip = item.tooltip || "";
                const status = item.status || "";
                const statusClass = item.statusClass ? item.statusClass.toLowerCase() : "";

                const style = typeStyleMap[type] || { iconText: () => "•", iconClass: "icon-generic" };
                const iconText = style.iconText(item);
                const iconClass = style.iconClass;

                // If avatar exists, show it instead of the colored circle
                const iconHtml = item.avatar && String(item.avatar).trim() !== ""
                    ? `<img class="result-avatar" src="${escapeAttr(item.avatar)}" alt="">`
                    : `<div class="result-icon ${iconClass}">${escapeHtml(iconText)}</div>`;

                html += `
                    <a href="${escapeAttr(safeUrl)}" class="result-item" title="${escapeAttr(tooltip)}">
                        ${iconHtml}
                        <div class="result-text">
                            <div class="result-title">${title}</div>
                            ${extra ? `<div class="result-sub">${extra}</div>` : ""}
                        </div>
                        ${status ? `
                            <div class="result-meta">
                                <span class="status-btn ${escapeAttr(statusClass)}">${escapeHtml(status)}</span>
                            </div>
                        ` : ""}
                    </a>
                `;
            });

            html += `</div>`;
        });

        html += `
                <div class="results-footer">
                    <button type="button" class="results-action" id="expandAllResults">
                        Expand All
                    </button>
                    <button type="button" class="results-action d-none" id="collapseAllResults">
                        Collapse All
                    </button>
                </div>
            </div>`;


        resultsBox.innerHTML = html;
        resultsBox.classList.remove("hideResults");

        bindAccordion();
        expandFirstGroup();
        bindExpandCollapseAll();
    }

    function bindExpandCollapseAll() {
        $("#expandAllResults").off("click").on("click", function () {
            $(".results-group").removeClass("d-none");
            $(".chevron").removeClass("collapsed");

            $(this).addClass("d-none");
            $("#collapseAllResults").removeClass("d-none");
        });

        $("#collapseAllResults").off("click").on("click", function () {
            $(".results-group").addClass("d-none");
            $(".chevron").addClass("collapsed");

            $(this).addClass("d-none");
            $("#expandAllResults").removeClass("d-none");
        });
    }


    function bindAccordion() {
        $(".results-header").off("click").on("click", function () {
            const targetId = $(this).data("target");
            const target = $("#" + cssEscape(targetId));
            const chevron = $("#" + cssEscape(targetId) + "-chevron");

            $(".results-group").not(target).addClass("d-none");
            $(".chevron").not(chevron).addClass("collapsed");

            target.toggleClass("d-none");
            chevron.toggleClass("collapsed");
        });
    }

    function expandFirstGroup() {
        const firstGroup = $(".results-group").first();
        if (!firstGroup.length) return;

        firstGroup.removeClass("d-none");
        $("#" + cssEscape(firstGroup.attr("id")) + "-chevron").removeClass("collapsed");
    }

    function renderEmpty() {
        resultsBox.innerHTML = `<div class="results-empty text-center">No results found</div>`;
        resultsBox.classList.remove("hideResults");
    }

    function renderError() {
        resultsBox.innerHTML = `<div class="results-empty error">Error fetching results</div>`;
        resultsBox.classList.remove("hideResults");
    }

    w.clientexec.globalSearch.clearSearch = function () {
        if (searchInput) searchInput.value = "";
        if (clearButton) clearButton.style.display = "none";
        if (resultsBox) {
            resultsBox.classList.add("hideResults");
            resultsBox.innerHTML = "";
        }
    };

    // Helpers
    function escapeHtml(str) {
        return String(str)
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#039;");
    }

    function escapeAttr(str) {
        // keep URLs intact but escape quotes/amps/etc for attributes
        return String(str)
            .replace(/&/g, "&amp;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#039;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");
    }

    function cssEscape(str) {
        // minimal escape for IDs that might contain spaces or special chars
        return String(str).replace(/([ #;?%&,.+*~\':"!^$[\]()=>|\/@])/g, "\\$1");
    }

    $(document).on("mousedown.clientexecSearch", function (e) {
        if (!resultsBox || resultsBox.classList.contains("hideResults")) {
            return;
        }

        const isInsideResults = resultsBox.contains(e.target);
        const isInsideInput = searchInput && searchInput.contains(e.target);

        if (!isInsideResults && !isInsideInput) {
            w.clientexec.globalSearch.clearSearch();
        }

        $(document).on("keydown.clientexecSearch", function (e) {
        if (e.key === "Escape") {
            w.clientexec.globalSearch.clearSearch();
        }
    });
});

})(jQuery, window, document);
