import { MARKET_DATA } from "../data/market-data.js";

class MenuSearch {
    constructor(modalSelector = "#searchModal", options = {}) {
        this.CONFIG = {
            DEBOUNCE_DELAY: 250,
            DEBOUNCE_FAST: 150,
            REQUEST_THROTTLE: 200,
            SCROLL_THROTTLE: 150,
            MAX_PAGES: 5,
            PER_PAGE: 50,
            LOADING_DELAY: 300,
            PRELOAD_DISTANCE: 200
        };
        this.clickConfig = {
            returnFields: options.returnFields || null,
            onItemClick: options.onItemClick || null,
            closeOnClick: options.closeOnClick !== undefined ? options.closeOnClick : true,
            showHoverButtons: options.showHoverButtons !== undefined ? options.showHoverButtons : null,
            showOverviewButton: options.showOverviewButton !== undefined ? options.showOverviewButton : true,
            showChartButton: options.showChartButton !== undefined ? options.showChartButton : true
        };
        this.favoriteConfig = {
            showFavorites: options.showFavorites || false,
            onFavoriteClick: options.onFavoriteClick || null,
            favoriteStorageKey: options.favoriteStorageKey || "screener_favorites",
            saveAssetType: options.saveAssetType || false,
            mergeFavorites: options.mergeFavorites || false,
            colors: options.favoriteColors || {
                "orange": "#F7931A",
                "red": "#EF4444",
                "green": "#10B981",
                "blue": "#3B82F6",
                "purple": "#8B5CF6",
                "cyan": "#26d0ce"
            }
        };
        this.favoriteState = {
            favorites: {},
            currentSymbol: null
        };
        this.iconType = options.iconType ?? (typeof ICON_TYPE !== "undefined" ? ICON_TYPE : ".svg");
        this.iconPath = options.iconPath ?? (typeof ICON_PATH !== "undefined" ? ICON_PATH : "");
        this.apiEndpoint = options.apiEndpoint ?? (typeof API_ENDPOINT !== "undefined" ? API_ENDPOINT : "");
        this.customApiEndpoint = !!options.apiEndpoint;
        this.baseUrl = options.baseUrl ?? (typeof BASE_URL !== "undefined" ? BASE_URL : "");
        this.filterTypes = options.filterTypes || null;
        this.showFilterPills = options.showFilterPills !== false;
        this.showDropdownFilters = options.showDropdownFilters !== false;
        this.customPlaceholder = options.placeholder || "";
        this.defaultFilter = options.defaultFilter || null;
        this.rootNode = options.rootNode || document;
        this.filterExchange = options.filterExchange || null;
        this.defaultDropdownFilters = options.defaultDropdownFilters || null;
        this.useStorage = options.useStorage !== undefined ? options.useStorage : true;
        this.modalSelector = modalSelector;
        this.modalId = modalSelector.replace("#", "");
        this.#createModal();
        this.modal = this.rootNode.querySelector(modalSelector);
        this.input = this.modal?.querySelector(`#${this.modalId}-input`);
        this.results = this.modal?.querySelector(`#${this.modalId}-results`);
        this.clearBtn = this.modal?.querySelector(`#${this.modalId}-clear`);
        this.dropdowns = this.modal?.querySelector(".dropdown-filters");
        this.filterPills = this.modal?.querySelectorAll(".filter-pill");
        this.state = {
            page: 1,
            loading: false,
            hasMore: true,
            lastQuery: "",
            defaultLoaded: false,
            lastRequestTime: 0,
            loadingRequestTime: 0,
            requestController: null,
            loadingTimeout: null
        };
        this.storagePrefix = options.storagePrefix || `menuSearch_${this.modalId}`;
        this.activeFilter = this.#getDefaultFilter();
        this.searchTimeout = null;
        this.#init();
    }
    open() {
        const customModal = CustomModal.getOrCreateInstance(this.modal);
        customModal?.show();
    }
    #init() {
        window.ICON_PATH = this.iconPath;
        window.API_ENDPOINT = this.apiEndpoint;
        window.BASE_URL = this.baseUrl;
        window.ICON_TYPE = this.iconType;
        if (this.favoriteConfig.showFavorites && !this.favoriteConfig.onFavoriteClick) {
            this.#loadFavorites();
        }
        this.#highlightActiveFilter();
        this.#bindEvents();
    }
    #highlightActiveFilter() {
        this.filterPills.forEach(pill => {
            pill.classList.remove("active");
            if (pill.dataset.searchFilter === this.activeFilter) {
                pill.classList.add("active");
            }
        });
    }
    #bindEvents() {
        this.dropdowns?.addEventListener("customSelectChange", e => {
            if (e.target.classList.contains("dropdown-select")) {
                this.#saveDropdownFilters();
                this.#resetState(this.input.value.trim());
                this.#performSearch(this.state.lastQuery);
            }
        });
        this.modal?.addEventListener("shown.cm.modal", () => {
            this.input.focus();
            const query = this.input.value.trim();
            if (this.#shouldSkipRequest(query)) return;
            if (this.activeFilter !== "global") {
                this.#generateFilterDropdowns().catch(console.warn);
            }
            this.#resetState(query);
            this.#performSearch(query);
        });
        this.clearBtn?.addEventListener("click", () => {
            this.input.value = "";
            this.input.focus();
            this.results.innerHTML = "";
            this.clearBtn.classList.add("hidden");
            this.#resetState("");
            this.#performSearch("");
        });
        this.input?.addEventListener("input", e => {
            const query = e.target.value.trim();
            if (this.clearBtn) {
                this.clearBtn.classList.toggle("hidden", query.length === 0);
            }
            if (query === this.state.lastQuery) return;
            if (query.length > 0) {
                e.target.classList.add("searching");
            } else {
                e.target.classList.remove("searching");
            }
            const delay = query.length < this.state.lastQuery.length ? this.CONFIG.DEBOUNCE_FAST : this.CONFIG.DEBOUNCE_DELAY;
            clearTimeout(this.searchTimeout);
            this.searchTimeout = setTimeout(() => {
                e.target.classList.remove("searching");
                this.#resetState(query);
                this.#performSearch(query);
            }, delay);
        });
        this.modal?.addEventListener("click", e => {
            const filterPill = e.target.closest(".filter-pill");
            if (!filterPill) return;
            const newFilter = filterPill.dataset.searchFilter;
            if (newFilter === this.activeFilter) return;
            this.filterPills.forEach(pill => pill.classList.remove("active"));
            filterPill.classList.add("active");
            this.activeFilter = newFilter;
            const coinsFilter = this.modal?.querySelector(".coins-filter");
            if (coinsFilter) {
                scrollToCenter(filterPill, coinsFilter);
            }
            if (this.useStorage) {
                STORAGE.set(`${this.storagePrefix}_selectType`, this.activeFilter);
            }
            if (this.activeFilter === "global") {
                this.dropdowns.innerHTML = "";
            } else {
                this.#generateFilterDropdowns().catch(console.warn);
            }
            const query = this.input.value.trim();
            this.#resetState(query);
            this.#performSearch(query);
        });
        this.results?.addEventListener("scroll", this.#throttle(() => {
            if (!this.#canLoadMore()) return;
            const scrollTop = this.results.scrollTop;
            const scrollHeight = this.results.scrollHeight;
            const clientHeight = this.results.clientHeight;
            if (scrollTop + clientHeight >= scrollHeight - this.CONFIG.PRELOAD_DISTANCE) {
                this.state.page++;
                this.#performSearch(this.state.lastQuery, true);
            }
        }, this.CONFIG.SCROLL_THROTTLE));
        const hasCallback = typeof this.clickConfig.onItemClick === "function";
        const hasHoverBtns = this.clickConfig.showHoverButtons !== null ? this.clickConfig.showHoverButtons : !hasCallback;
        this.results?.addEventListener("click", e => {
            if (e.target.closest(".fav-star-btn")) return;
            const actionBtn = e.target.closest(".hover-action-btn");
            const resultItem = e.target.closest(".search-result-item");
            if (!resultItem) return;
            if (actionBtn && hasHoverBtns) {
                e.preventDefault();
                e.stopPropagation();
                const action = actionBtn.dataset.action;
                const url = actionBtn.dataset.url;
                if (hasCallback) {
                    this.clickConfig.onItemClick(this.#extractItemData(resultItem), action);
                } else {
                    if (action === "chart") {
                        window.open(url, "_blank");
                    } else {
                        window.location.href = url;
                    }
                }
                if (this.clickConfig.closeOnClick) {
                    const customModal = CustomModal.getInstance(this.modal);
                    customModal?.hide();
                }
                return false;
            }
            if (hasCallback) {
                e.preventDefault();
                e.stopPropagation();
                this.clickConfig.onItemClick(this.#extractItemData(resultItem), "overview");
                if (this.clickConfig.closeOnClick) {
                    const customModal = CustomModal.getInstance(this.modal);
                    customModal?.hide();
                }
            } else {
                const overviewBtn = resultItem.querySelector('.hover-action-btn[data-action="overview"]');
                if (overviewBtn) {
                    window.location.href = overviewBtn.dataset.url;
                }
            }
        });
        if (this.favoriteConfig.showFavorites) {
            this.results?.addEventListener("click", e => {
                const starBtn = e.target.closest(".fav-star-btn");
                if (!starBtn) return;
                e.preventDefault();
                e.stopPropagation();
                const resultItem = starBtn.closest(".search-result-item");
                if (!resultItem) return;
                const ticker = resultItem.dataset.ticker;
                const itemData = this.#extractItemData(resultItem);
                const existingFav = this.favoriteState.favorites[ticker];
                if (existingFav && !this.favoriteConfig.onFavoriteClick) {
                    this.#removeFavorite(ticker);
                    return;
                }
                this.favoriteState.currentSymbol = ticker;
                this.favoriteState.currentItemData = itemData;
                if (!this.favoriteConfig.onFavoriteClick) {
                    if (this.favoriteConfig.saveAssetType) {
                        const assetType = resultItem.dataset.type || "crypto";
                        this.favoriteState.favorites[ticker] = {
                            color: "orange",
                            type: assetType
                        };
                    } else {
                        this.favoriteState.favorites[ticker] = "orange";
                    }
                    this.#saveFavorites();
                    this.#updateFavoriteButtonUI(ticker, "orange");
                }
                this.#showColorPickerAt(starBtn);
            });
            const colorPicker = this.modal?.querySelector(".menu-search-color-picker");
            if (colorPicker) {
                colorPicker.addEventListener("click", e => {
                    const colorOption = e.target.closest(".color-option");
                    if (!colorOption) return;
                    const color = colorOption.dataset.color;
                    this.#handleFavoriteColorSelection(color, this.favoriteState.currentItemData);
                });
            }
            document.addEventListener("click", e => {
                const isStarBtn = e.target.closest(".fav-star-btn");
                const isColorPicker = e.target.closest(".menu-search-color-picker");
                if (!isStarBtn && !isColorPicker) {
                    this.#hideColorPicker();
                }
            });
        }
    }
    #resetState(query = "") {
        this.state.page = 1;
        this.state.loading = false;
        this.state.hasMore = true;
        this.state.lastQuery = query;
    }
    #shouldSkipRequest(query) {
        return query === this.state.lastQuery && (!query && this.state.defaultLoaded || query && this.results.children.length > 0);
    }
    #canLoadMore() {
        return !this.state.loading && this.state.hasMore && this.state.page < this.CONFIG.MAX_PAGES;
    }
    async #performSearch(query = "", append = false) {
        this.#clearLoadingTimeout();
        if (this.activeFilter === "global" || this.activeFilter === "all") {
            if (!append) {
                this.results.innerHTML = this.#getLoadingHTML();
            }
        } else {
            if (!append) {
                const loadingRequestTime = Date.now();
                this.state.loadingRequestTime = loadingRequestTime;
                this.state.loadingTimeout = setTimeout(() => {
                    if (this.state.loading && this.state.loadingRequestTime === loadingRequestTime) {
                        this.results.innerHTML = this.#getLoadingHTML();
                    }
                }, this.CONFIG.LOADING_DELAY);
            }
        }
        const now = Date.now();
        if (now - this.state.lastRequestTime < this.CONFIG.REQUEST_THROTTLE) {
            this.#clearLoadingTimeout();
            return;
        }
        if (this.state.loading) {
            this.#clearLoadingTimeout();
            return;
        }
        this.state.loading = true;
        this.state.lastQuery = query;
        this.state.lastRequestTime = now;
        if (this.state.requestController) {
            this.state.requestController.abort();
        }
        this.state.requestController = new AbortController;
        const filterValues = this.#buildFilterValues();
        const trimmedQuery = query.trim();
        let search = trimmedQuery || (this.filterExchange ? "" : this.#getDefaultSymbols(filterValues));
        const STOCK_LIKE_ASSETS = [ "stock", "fund" ];
        if (trimmedQuery === "" && STOCK_LIKE_ASSETS.includes(this.activeFilter)) {
            filterValues.is_primary = 1;
        }
        const postData = {
            per_page: this.CONFIG.PER_PAGE,
            page: this.state.page,
            search: search,
            type: this.activeFilter,
            merge: "profile,meta",
            columns: "profile,meta.is_primary",
            ...filterValues,
            ...this.filterExchange ? {
                exchange: this.filterExchange
            } : {}
        };
        if (append && !this.results.querySelector(".menu-search-result-more-loading")) {
            this.results.insertAdjacentHTML("beforeend", `\n                <div class="menu-search-result-more-loading">\n                    <div class="search-result-item skeleton-item">\n                        <div class="search-result-info">\n                            <div class="search-result-icon-container">\n                                <span class="skeleton skeleton-circle"></span>\n                            </div>\n                            <div class="search-result-details">\n                                <div class="search-result-symbol"><span class="skeleton skeleton-symbol"></span></div>\n                                <div class="search-result-name"><span class="skeleton skeleton-name"></span></div>\n                            </div>\n                        </div>\n                        <div class="search-result-exchange">\n                            <div class="search-result-exchange-type">\n                                <span class="skeleton skeleton-type"></span>\n                                <div class="skeleton skeleton-exchange-badge"></div>\n                            </div>\n                            <div class="search-result-icon-container">\n                                <span class="skeleton skeleton-circle"></span>\n                            </div>\n                        </div>\n                    </div>\n                    <div class="search-result-item skeleton-item">\n                        <div class="search-result-info">\n                            <div class="search-result-icon-container">\n                                <span class="skeleton skeleton-circle"></span>\n                            </div>\n                            <div class="search-result-details">\n                                <div class="search-result-symbol"><span class="skeleton skeleton-symbol"></span></div>\n                                <div class="search-result-name"><span class="skeleton skeleton-name"></span></div>\n                            </div>\n                        </div>\n                        <div class="search-result-exchange">\n                            <div class="search-result-exchange-type">\n                                <span class="skeleton skeleton-type"></span>\n                                <div class="skeleton skeleton-exchange-badge"></div>\n                            </div>\n                            <div class="search-result-icon-container">\n                                <span class="skeleton skeleton-circle"></span>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            `);
        }
        try {
            const apiUrl = this.customApiEndpoint ? this.apiEndpoint : `${this.apiEndpoint}forex/search`;
            const result = await sendPostRequest(apiUrl, postData, {
                signal: this.state.requestController.signal
            });
            this.#clearLoadingTimeout();
            this.#handleSuccess(result, query, append);
        } catch (error) {
            this.#clearLoadingTimeout();
            if (!append && error.name !== "AbortError") {
                this.#handleError();
            }
        }
    }
    #getDefaultSymbols(filterValues) {
        const hasFilters = filterValues && Object.keys(filterValues).length > 0;
        if (hasFilters) return "";
        const defaults = {
            crypto: {
                DEX: "uni,cake,1inch,sushi,dydx,crv",
                default: "btcusdt,ethusdt,solusdt,bnbusdt,xrpusdt,adausdt"
            },
            forex: "eur,gbp,jpy,aud,cad,chf",
            stock: "aapl,msft,googl,amzn,tsla,nvda,meta,abbv",
            fund: "spy,voo,qqq,vti,vig,vug",
            futures: "btcusdt,ethusdt,solusd,xrpusd",
            dex: "spxwbnb,xmww,1inch,sushi,dydx,crv",
            indices: "spx,nifty,dxy,btcusd,btc.d,nasdaq",
            global: "btcusdt,ethusdt,aapl,xauusd,tsla,googl"
        };
        if (this.activeFilter === "crypto") {
            return filterValues.type === "DEX" ? defaults.crypto.DEX : defaults.crypto.default;
        }
        return defaults[this.activeFilter] || defaults.global;
    }
    #buildFilterValues() {
        const filterValues = {};
        const dropdownSelects = this.dropdowns?.querySelectorAll(".dropdown-select") || [];
        dropdownSelects.forEach(dropdown => {
            const filterType = dropdown.dataset.filterType;
            const api = dropdown.customSelectAPI;
            const value = api?.getValue();
            if (value && value !== "all" && value !== "") {
                filterValues[filterType] = value;
            }
        });
        if (Object.keys(filterValues).length === 0) {
            if (this.useStorage) {
                const savedFilters = STORAGE.get(`${this.storagePrefix}_filters_${this.activeFilter}`);
                if (savedFilters) {
                    Object.assign(filterValues, savedFilters);
                }
            }
            if (Object.keys(filterValues).length === 0 && this.defaultDropdownFilters) {
                Object.assign(filterValues, this.defaultDropdownFilters);
            }
        }
        return filterValues;
    }
    #handleSuccess(response, query, append) {
        this.input.classList.remove("searching");
        this.state.loading = false;
        const loadingElement = this.modal?.querySelector(".menu-search-result-more-loading");
        loadingElement?.remove();
        const results = Array.isArray(response) ? response : response?.response || response?.data || [];
        if (results.length === 0) {
            if (append) {
                this.state.hasMore = false;
                return;
            }
            this.#showEmptyState();
            return;
        }
        const html = results.map(item => this.#renderSearchItem(item)).join("");
        if (append) {
            this.results.insertAdjacentHTML("beforeend", html);
        } else {
            this.results.innerHTML = html;
            this.results.scrollTop = 0;
        }
        this.state.hasMore = results.length >= this.CONFIG.PER_PAGE && this.state.page < this.CONFIG.MAX_PAGES;
        if (!query && this.state.page === 1) {
            this.state.defaultLoaded = true;
        }
    }
    #handleError() {
        this.input.classList.remove("searching");
        this.state.loading = false;
        const loadingElement = this.modal?.querySelector(".menu-search-result-more-loading");
        loadingElement?.remove();
        this.#showEmptyState();
    }
    #clearLoadingTimeout() {
        if (this.state.loadingTimeout) {
            clearTimeout(this.state.loadingTimeout);
            this.state.loadingTimeout = null;
        }
    }
    #showEmptyState() {
        const noSymbolsText = getLang("menu_search.empty_state.no_symbols", "No symbols found");
        const tryDifferentText = getLang("menu_search.empty_state.try_different", "Try different keywords or adjust filters");
        this.results.innerHTML = `\n            <div class="menu-search-noresult">\n                <div class="mb-2">\n                    <svg width="200" height="200" fill="none" stroke="none">\n                        <use href="#magnifier-char"></use>\n                    </svg>\n                </div>\n                <div class="fw-medium">${noSymbolsText}</div>\n                <div class="small mt-1">${tryDifferentText}</div>\n            </div>\n        `;
        this.state.hasMore = false;
    }
    #extractItemData(item) {
        const itemDataStr = item.dataset.itemData || "{}";
        const itemData = JSON.parse(itemDataStr.replace(/&quot;/g, '"'));
        return itemData;
    }
    #prepareItemData(item) {
        const profile = item.profile || {};
        const meta = item.meta || {};
        if (!this.clickConfig.returnFields || !Array.isArray(this.clickConfig.returnFields)) {
            const result = {
                profile: profile,
                meta: meta
            };
            Object.keys(item).forEach(key => {
                if (key !== "profile" && key !== "meta" && key !== "update") {
                    result[key] = item[key];
                }
            });
            return result;
        }
        const result = {
            profile: {},
            meta: {}
        };
        let hasProfileFields = false;
        let hasMetaFields = false;
        let hasRootFields = false;
        this.clickConfig.returnFields.forEach(field => {
            if (field.includes(".")) {
                const [source, fieldName] = field.split(".");
                if (source === "profile" && profile.hasOwnProperty(fieldName)) {
                    result.profile[fieldName] = profile[fieldName];
                    hasProfileFields = true;
                } else if (source === "meta" && meta.hasOwnProperty(fieldName)) {
                    result.meta[fieldName] = meta[fieldName];
                    hasMetaFields = true;
                }
            } else {
                if (item.hasOwnProperty(field) && field !== "profile" && field !== "meta" && field !== "update") {
                    result[field] = item[field];
                    hasRootFields = true;
                } else if (profile.hasOwnProperty(field)) {
                    result.profile[field] = profile[field];
                    hasProfileFields = true;
                } else if (meta.hasOwnProperty(field)) {
                    result.meta[field] = meta[field];
                    hasMetaFields = true;
                }
            }
        });
        const finalResult = {};
        if (hasProfileFields && Object.keys(result.profile).length > 0) {
            finalResult.profile = result.profile;
        }
        if (hasMetaFields && Object.keys(result.meta).length > 0) {
            finalResult.meta = result.meta;
        }
        Object.keys(result).forEach(key => {
            if (key !== "profile" && key !== "meta") {
                finalResult[key] = result[key];
            }
        });
        return finalResult;
    }
    #renderSearchItem(item) {
        const profile = item.profile || {};
        const meta = item.meta || {};
        const {symbol: symbol = "", name: name = "", exchange: exchange = "", type: type = "", sub_type: sub_type = "", base_logo: base_logo = "", curr_logo: curr_logo = "", exc_logo: exc_logo = ""} = profile;
        const url = buildDynamicUrl(null, {
            symbol: symbol,
            exchange: exchange,
            type: type
        });
        const typeDisplay = this.activeFilter === "global" || this.activeFilter === "all" ? `${type} / ${sub_type}` : sub_type;
        const coinImagesHtml = generateCoinLogoHtml(profile);
        const excLogoHtml = `<div class="search-result-icon-container">${generateCoinLogoHtml({
            "base_logo": exc_logo
        })}</div>`;
        let symbolDisplay = symbol;
        if (meta.is_primary && (type === "stock" || sub_type === "dr")) {
            const primaryListingText = getLang("menu_search.actions.primary_listing", "Primary listing");
            symbolDisplay = meta.is_primary === 1 ? `${symbol}<svg width="18" height="18" fill="currentColor" stroke="currentColor" data-tooltip-title="${primaryListingText}"><use href="#primary"></use></svg>` : symbol;
        }
        const itemDataToStore = this.#prepareItemData(item);
        const itemDataJson = JSON.stringify(itemDataToStore).replace(/"/g, "&quot;");
        let itemData = "";
        if (this.clickConfig.onItemClick) {
            itemData = `data-item-data="${itemDataJson}"`;
        }
        const seeOverviewText = getLang("menu_search.actions.see_overview", "See Overview");
        const launchChartText = getLang("menu_search.actions.launch_chart", "Launch Chart");
        const showBtns = this.clickConfig.showHoverButtons !== null ? this.clickConfig.showHoverButtons : typeof this.clickConfig.onItemClick !== "function";
        let hoverButtonsHtml = "";
        if (showBtns) {
            const overviewBtn = this.clickConfig.showOverviewButton !== false ? `<button type="button" class="hover-action-btn active" data-action="overview" data-url="${url}">${seeOverviewText}</button>` : "";
            const chartBtn = this.clickConfig.showChartButton !== false ? `<button type="button" class="hover-action-btn chart-btn" data-action="chart" data-url="${typeof BASE_PATH !== "undefined" ? BASE_PATH : this.baseUrl}chart?symbol=${encodeURIComponent(item.ticker || "")}">${launchChartText}</button>` : "";
            if (overviewBtn || chartBtn) {
                hoverButtonsHtml = `<div class="search-result-hover-actions">${overviewBtn}${chartBtn}</div>`;
            }
        }
        let favStarHtml = "";
        if (this.favoriteConfig.showFavorites) {
            const ticker = item.ticker || `${exchange}:${symbol}`;
            const storedFav = this.favoriteState.favorites[ticker];
            const storedColor = typeof storedFav === "string" ? storedFav : storedFav?.color;
            const colorCode = storedColor ? this.favoriteConfig.colors[storedColor] : null;
            const activeClass = storedColor ? " active" : "";
            const fillAttr = colorCode ? colorCode : "none";
            const strokeAttr = colorCode ? colorCode : "currentColor";
            favStarHtml = `<button class="fav-star-btn${activeClass}" type="button">\n                <svg width="18" height="18" fill="${fillAttr}" stroke="${strokeAttr}"><use href="#star"></use></svg>\n            </button>`;
        }
        const contentHtml = `\n            <div class="search-result-item" data-symbol="${symbol}" data-ticker="${item.ticker || `${exchange}:${symbol}`}" data-type="${type}" ${itemData}>\n                ${favStarHtml}\n                <div class="search-result-info">\n                    <div class="search-result-icon-container">\n                        ${coinImagesHtml}\n                    </div>\n                    <div class="search-result-details">\n                        <div class="search-result-symbol">${symbolDisplay}</div>\n                        <div class="search-result-name">${name || symbol}</div>\n                    </div>\n                </div>\n                <div class="search-result-exchange">\n                    <div class="search-result-exchange-type">\n                        <span>${typeDisplay}</span>\n                        <div class="search-result-exchange-badge">${exchange}</div>\n                    </div>\n                    ${excLogoHtml}\n                </div>\n                ${hoverButtonsHtml}\n            </div>\n        `;
        return contentHtml;
    }
    #getLoadingHTML() {
        const skeletonCount = 14;
        let skeletonHtml = "";
        for (let i = 0; i < skeletonCount; i++) {
            skeletonHtml += `\n                <div class="search-result-item skeleton-item">\n                    <div class="search-result-info">\n                        <div class="search-result-icon-container">\n                            <span class="skeleton skeleton-circle"></span>\n                        </div>\n                        <div class="search-result-details">\n                            <div class="search-result-symbol"><span class="skeleton skeleton-symbol"></span></div>\n                            <div class="search-result-name"><span class="skeleton skeleton-name"></span></div>\n                        </div>\n                    </div>\n                    <div class="search-result-exchange">\n                        <div class="search-result-exchange-type">\n                            <span class="skeleton skeleton-type"></span>\n                            <div class="skeleton skeleton-exchange-badge"></div>\n                        </div>\n                        <div class="search-result-icon-container">\n                            <span class="skeleton skeleton-circle"></span>\n                        </div>\n                    </div>\n                </div>\n            `;
        }
        return `<div class="menu-search-skeleton-loading">${skeletonHtml}</div>`;
    }
    #saveDropdownFilters() {
        const filterValues = {};
        const dropdownSelects = this.dropdowns?.querySelectorAll(".dropdown-select") || [];
        dropdownSelects.forEach(dropdown => {
            const property = dropdown.dataset.filterType;
            const api = dropdown.customSelectAPI;
            const value = api?.getValue();
            if (value && value !== "") {
                filterValues[property] = value;
            }
        });
        if (this.useStorage) {
            STORAGE.set(`${this.storagePrefix}_filters_${this.activeFilter}`, filterValues);
        }
    }
    async #generateFilterDropdowns() {
        if (!this.dropdowns) {
            return Promise.reject("Container not found");
        }
        if (this.filterExchange) {
            this.dropdowns.innerHTML = "";
            return Promise.resolve();
        }
        const html = this.#buildDropdownsHtml();
        if (!html) {
            this.dropdowns.innerHTML = "";
            return Promise.reject("No dropdown data");
        }
        return new Promise(resolve => {
            this.dropdowns.innerHTML = html;
            requestAnimationFrame(() => {
                initCustomSelects(this.modalSelector, this.rootNode !== document ? this.rootNode : null);
            });
        });
    }
    #buildDropdownsHtml() {
        const data = MARKET_DATA[this.activeFilter];
        if (!data) return "";
        const storedFilters = this.useStorage ? STORAGE.get(`${this.storagePrefix}_filters_${this.activeFilter}`) || {} : {};
        const savedFilters = Object.keys(storedFilters).length ? storedFilters : this.defaultDropdownFilters || {};
        return Object.entries(data).filter(([, items]) => items && typeof items === "object" && Object.keys(items).length).map(([property, items]) => this.#buildDropdownHtml(property, items, savedFilters)).join("");
    }
    #buildDropdownHtml(property, items, savedFilters) {
        const dropdownId = `${this.activeFilter}_${property}_select`;
        const isExchange = property === "exchange";
        const isCountry = property === "country";
        const hasSearch = Object.keys(items).length > 7;
        const savedValue = savedFilters[property];
        const firstOptionText = this.#getFirstOptionText(property);
        const firstOptionHTML = isExchange || isCountry ? this.#getIconOptionHTML(firstOptionText, "#global") : firstOptionText;
        const savedItem = savedValue ? Array.isArray(items) ? items.find(i => i.value === savedValue) : items[savedValue] : null;
        const triggerDisplayText = savedItem ? this.#getTriggerDisplayText(savedValue, savedItem, property, isExchange, isCountry) : firstOptionHTML;
        const firstOptionSelected = !savedValue ? "selected" : "";
        return `\n            <div class="dropdown-select filter-dropdown" id="${dropdownId}" \n                 data-filter-type="${property}" ${hasSearch ? 'data-search="true"' : ""}>\n                <div class="select-trigger">\n                    <span class="select-trigger-text">${triggerDisplayText}</span>\n                    <svg width="18" height="18" class="select-arrow" fill="none" stroke="currentColor">\n                        <use href="#chevron-down"></use>\n                    </svg>\n                </div>\n                <div class="select-dropdown">\n                    <ul class="select-options">\n                        <li class="select-option ${firstOptionSelected}" data-value="">\n                            ${firstOptionHTML}\n                        </li>\n                        ${this.#buildOptionsHTML(items, property, isExchange, isCountry, savedValue)}\n                    </ul>\n                </div>\n            </div>\n        `;
    }
    #getFirstOptionText(property) {
        const allCountriesText = getLang("menu_search.dropdowns.all_countries", "All countries");
        const allTypesText = getLang("menu_search.dropdowns.all_types", "All types");
        const allExchangeTypesText = getLang("menu_search.dropdowns.all_exchange_types", "All exchange types");
        const allSectorsText = getLang("menu_search.dropdowns.all_sectors", "All Sectors");
        const allExchangesText = getLang("menu_search.dropdowns.all_exchanges", "All exchanges");
        const textMap = {
            country: allCountriesText,
            sub_type: allTypesText,
            type: this.activeFilter === "crypto" ? allExchangeTypesText : `All ${property}s`,
            sector: allSectorsText,
            exchange: allExchangesText
        };
        return textMap[property] || `All ${property.replace(/_/g, " ")}s`;
    }
    #getIconOptionHTML(text, iconHref) {
        return `\n            <span class="select-option-img">\n                <div class="flag-icon-container">\n                    <svg width="100%" height="100%" fill="none" stroke="currentColor">\n                        <use href="${iconHref}"></use>\n                    </svg>\n                </div>\n                ${text}\n            </span>\n        `;
    }
    #getTriggerDisplayText(savedValue, itemLabel, property, isExchange, isCountry) {
        if (isExchange || isCountry) {
            const itemIcon = isExchange ? itemLabel?.icon || savedValue : savedValue;
            const displayLabel = isExchange ? itemLabel?.label || itemLabel : isCountry ? itemLabel.name : itemLabel;
            const itemValue = isCountry ? itemLabel.name : displayLabel;
            const img = `${this.iconPath}${property}/${itemIcon}${this.iconType}`;
            return `\n                <span class="select-option-img">\n                    <div class="flag-icon-container">\n                        <img data-src="${img}" alt="${displayLabel}" class="flag-img">\n                    </div>\n                    ${itemValue}\n                </span>\n            `;
        }
        return itemLabel;
    }
    #buildOptionsHTML(items, property, isExchange, isCountry, savedValue) {
        return Object.entries(items).map(([itemKey, itemLabel]) => {
            const optionValue = isExchange ? itemLabel?.value || itemKey : itemKey;
            const isSelected = savedValue === optionValue ? "selected" : "";
            if (isExchange || isCountry) {
                const itemIcon = isExchange ? itemLabel?.icon || itemKey : itemKey;
                const displayLabel = isExchange ? itemLabel?.label || itemLabel : isCountry ? itemLabel.name : itemLabel;
                const itemValue = isCountry ? itemLabel.name : displayLabel;
                const img = `${this.iconPath}${property}/${itemIcon}${this.iconType}`;
                return `\n                        <li class="select-option ${isSelected}" data-value="${optionValue}">\n                            <span class="select-option-img">\n                                <div class="flag-icon-container">\n                                    <img data-src="${img}" alt="${displayLabel}" class="flag-img">\n                                </div> \n                                ${itemValue}\n                            </span>\n                        </li>\n                    `;
            }
            return `<li class="select-option ${isSelected}" data-value="${itemKey}">${itemLabel}</li>`;
        }).join("");
    }
    #throttle(func, delay) {
        let timeout;
        let previous = 0;
        return function(...args) {
            const now = Date.now();
            const remaining = delay - (now - previous);
            if (remaining <= 0 || remaining > delay) {
                if (timeout) {
                    clearTimeout(timeout);
                    timeout = null;
                }
                previous = now;
                func.apply(this, args);
            } else if (!timeout) {
                timeout = setTimeout(() => {
                    previous = Date.now();
                    timeout = null;
                    func.apply(this, args);
                }, remaining);
            }
        };
    }
    #createModal() {
        const existCheck = this.rootNode.getElementById ? this.rootNode.getElementById(this.modalId) : this.rootNode.querySelector("#" + this.modalId);
        if (existCheck) {
            return;
        }
        const filterPillsHtml = this.#buildFilterPillsHtml();
        const showCoinsFilter = this.showFilterPills && this.#shouldShowCoinsFilter();
        const placeholderText = this.customPlaceholder || getLang("menu_search.placeholder", "Symbol, eg. BTCUSD, AAPL, GOLD");
        const clearText = getLang("menu_search.clear", "Clear");
        const modalHTML = `\n            <div class="modal" id="${this.modalId}" tabindex="-1" aria-labelledby="${this.modalId}Label" data-custom-modal="true">\n                <div class="modal-dialog modal-lg modal-dialog-centered">\n                    <div class="modal-content search-modal-content">\n                        \x3c!-- Modal Header with Search --\x3e\n                        <div class="modal-header search-modal-header">\n                            <div class="search-input-container">\n                                <svg width="24" height="24" class="search-icon" fill="none" stroke="currentColor">\n                                    <use href="#search"></use>\n                                </svg>\n                                <input type="text" class="form-control search-modal-input"\n                                       placeholder="${placeholderText}"\n                                       id="${this.modalId}-input"\n                                       autocomplete="off">\n                                <button type="button"\n                                        id="${this.modalId}-clear"\n                                        class="search-clear hidden">\n                                    ${clearText}\n                                </button>\n                            </div>\n                            <span class="custom-modal-close" data-cm-dismiss="custom-modal">\n                                <svg width="22" height="22" fill="none" stroke="currentColor">\n                                    <use href="#x"></use>\n                                </svg>\n                            </span>\n                        </div>\n\n                        \x3c!-- Category Filters --\x3e\n                        <div class="modal-body p-0">\n                            ${showCoinsFilter || this.showDropdownFilters ? `<div class="search-filters-container">\n                                ${showCoinsFilter ? `<div class="coins-filter">${filterPillsHtml}</div>` : ""}\n                                ${this.showDropdownFilters ? '<div class="dropdown-filters"></div>' : ""}\n                            </div>` : ""}\n\n                            \x3c!-- Search Results --\x3e\n                            <div class="search-results" id="${this.modalId}-results"></div>\n                        </div>\n\n                        \x3c!-- Color Picker for Favorites --\x3e\n                        ${this.favoriteConfig.showFavorites ? `\n                        <div class="menu-search-color-picker" id="${this.modalId}-colorPicker">\n                            <div class="color-options">\n                                ${Object.entries(this.favoriteConfig.colors).map(([colorName, colorCode]) => `<div class="color-option" data-color="${colorName}" style="background-color: ${colorCode}"></div>`).join("")}\n                            </div>\n                        </div>\n                        ` : ""}\n                    </div>\n                </div>\n            </div>\n        `;
        const appendTarget = this.rootNode === document ? document.body : this.rootNode;
        if (appendTarget.insertAdjacentHTML) {
            appendTarget.insertAdjacentHTML("beforeend", modalHTML);
        } else {
            const temp = document.createElement("div");
            temp.innerHTML = modalHTML;
            while (temp.firstChild) appendTarget.appendChild(temp.firstChild);
        }
    }
    #buildFilterPillsHtml() {
        const allFilters = {
            global: getLang("menu_search.filters.all", "All"),
            stock: getLang("menu_search.filters.stocks", "Stocks"),
            fund: getLang("menu_search.filters.funds", "Funds"),
            futures: getLang("menu_search.filters.futures", "Futures"),
            forex: getLang("menu_search.filters.forex", "Forex"),
            crypto: getLang("menu_search.filters.crypto", "Crypto"),
            dex: getLang("menu_search.filters.dex", "DEX"),
            indices: getLang("menu_search.filters.indices", "Indices")
        };
        if (!this.filterTypes || !Array.isArray(this.filterTypes) || this.filterTypes.length === 0) {
            return Object.entries(allFilters).map(([key, label]) => `<div class="filter-pill" data-search-filter="${key}">${label}</div>`).join("");
        }
        return this.filterTypes.filter(type => allFilters[type] && type !== "global").map(type => `<div class="filter-pill" data-search-filter="${type}">${allFilters[type]}</div>`).join("");
    }
    #shouldShowCoinsFilter() {
        if (!this.filterTypes || !Array.isArray(this.filterTypes)) {
            return true;
        }
        const visibleFilters = this.filterTypes.filter(type => type !== "global");
        return visibleFilters.length > 1;
    }
    #getDefaultFilter() {
        const savedFilter = this.useStorage ? STORAGE.get(`${this.storagePrefix}_selectType`) : null;
        if (!this.filterTypes || !Array.isArray(this.filterTypes) || this.filterTypes.length === 0) {
            return savedFilter || this.defaultFilter || "global";
        }
        const allowedFilters = this.filterTypes.filter(type => type !== "global");
        if (savedFilter && allowedFilters.includes(savedFilter)) {
            return savedFilter;
        }
        return allowedFilters[0] || "global";
    }
    #loadFavorites() {
        const stored = STORAGE.get(this.favoriteConfig.favoriteStorageKey);
        if (stored && typeof stored === "object") {
            this.favoriteState.favorites = stored;
        }
    }
    #saveFavorites() {
        if (this.favoriteConfig.mergeFavorites) {
            const freshStored = STORAGE.get(this.favoriteConfig.favoriteStorageKey) || {};
            const mergedFavorites = {
                ...freshStored,
                ...this.favoriteState.favorites
            };
            this.favoriteState.favorites = mergedFavorites;
            STORAGE.set(this.favoriteConfig.favoriteStorageKey, mergedFavorites);
        } else {
            STORAGE.set(this.favoriteConfig.favoriteStorageKey, this.favoriteState.favorites);
        }
    }
    #deleteFavoriteFromStorage(ticker) {
        const freshStored = STORAGE.get(this.favoriteConfig.favoriteStorageKey) || {};
        delete freshStored[ticker];
        STORAGE.set(this.favoriteConfig.favoriteStorageKey, freshStored);
    }
    #showColorPickerAt(trigger) {
        const colorPicker = this.modal?.querySelector(".menu-search-color-picker");
        if (!colorPicker || !trigger) return;
        const rect = trigger.getBoundingClientRect();
        const modalRect = this.modal.querySelector(".modal-content").getBoundingClientRect();
        const isRTL = document.documentElement.dir === "rtl";
        colorPicker.style.top = rect.bottom - modalRect.top + 5 + "px";
        if (isRTL) {
            colorPicker.style.left = "auto";
            colorPicker.style.right = modalRect.right - rect.right + "px";
        } else {
            colorPicker.style.right = "auto";
            colorPicker.style.left = rect.left - modalRect.left + "px";
        }
        colorPicker.classList.add("show");
    }
    #hideColorPicker() {
        const colorPicker = this.modal?.querySelector(".menu-search-color-picker");
        if (colorPicker) {
            colorPicker.classList.remove("show");
        }
        this.favoriteState.currentSymbol = null;
    }
    #handleFavoriteColorSelection(color, itemData) {
        const ticker = this.favoriteState.currentSymbol;
        if (typeof this.favoriteConfig.onFavoriteClick === "function") {
            this.favoriteConfig.onFavoriteClick(itemData, color);
            if (this.clickConfig.closeOnClick) {
                const customModal = CustomModal.getInstance(this.modal);
                customModal?.hide();
            }
        } else {
            if (this.favoriteConfig.saveAssetType) {
                const existingFav = this.favoriteState.favorites[ticker];
                const assetType = (typeof existingFav === "object" ? existingFav?.type : null) || itemData?.profile?.type || "crypto";
                this.favoriteState.favorites[ticker] = {
                    color: color,
                    type: assetType
                };
            } else {
                this.favoriteState.favorites[ticker] = color;
            }
            this.#saveFavorites();
            this.#updateFavoriteButtonUI(ticker, color);
        }
        this.#hideColorPicker();
    }
    #removeFavorite(ticker) {
        delete this.favoriteState.favorites[ticker];
        if (!this.favoriteConfig.onFavoriteClick) {
            if (this.favoriteConfig.mergeFavorites) {
                this.#deleteFavoriteFromStorage(ticker);
            } else {
                this.#saveFavorites();
            }
        }
        this.#updateFavoriteButtonUI(ticker, null);
    }
    #updateFavoriteButtonUI(ticker, color) {
        const item = this.results?.querySelector(`.search-result-item[data-ticker="${ticker}"]`);
        if (!item) return;
        const starBtn = item.querySelector(".fav-star-btn");
        if (!starBtn) return;
        const svg = starBtn.querySelector("svg");
        if (!svg) return;
        if (color) {
            const colorCode = this.favoriteConfig.colors[color];
            starBtn.classList.add("active");
            svg.setAttribute("fill", colorCode);
            svg.setAttribute("stroke", colorCode);
        } else {
            starBtn.classList.remove("active");
            svg.setAttribute("fill", "none");
            svg.setAttribute("stroke", "currentColor");
        }
    }
    #applyStoredFavorites() {
        if (!this.favoriteConfig.showFavorites) return;
        if (this.favoriteConfig.onFavoriteClick) return;
        const favoriteKeys = Object.keys(this.favoriteState.favorites);
        if (favoriteKeys.length === 0) return;
        favoriteKeys.forEach(ticker => {
            const fav = this.favoriteState.favorites[ticker];
            const color = typeof fav === "string" ? fav : fav?.color;
            this.#updateFavoriteButtonUI(ticker, color);
        });
    }
}

export { MenuSearch };

if (typeof window !== "undefined") {
    window.MenuSearch = MenuSearch;
}