{
  "version": 3,
  "sources": ["../src/smart-search.js"],
  "sourcesContent": ["/**\n * Smart Search \u2014 Alpine.js autocomplete component\n * \u041F\u0430\u0440\u0441\u0438\u0442 \u043F\u043E\u0438\u0441\u043A\u043E\u0432\u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441 \u0432 \u0444\u0438\u043B\u044C\u0442\u0440\u044B \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430 \u0447\u0435\u0440\u0435\u0437 API\n * Used in: templates/core/index.html, templates/core/city_landing.html\n *\n * Typing placeholder: \u0434\u0438\u043D\u0430\u043C\u0438\u0447\u0435\u0441\u043A\u0438\u0439 \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440 \u0441 \u044D\u0444\u0444\u0435\u043A\u0442\u043E\u043C \u043F\u0435\u0447\u0430\u0442\u0438,\n * \u0438\u0437\u0432\u043B\u0435\u043A\u0430\u0435\u0442 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F \u043F\u043E\u0434\u0443\u0441\u043B\u0443\u0433 \u0438\u0437 CATALOG_NAV_CONFIG.\n */\nfunction smartSearch() {\n    return {\n        query: '',\n        suggestions: [],\n        noResults: false,\n        isOpen: false,\n        selectedIndex: -1,\n        loading: false,\n        debounceTimer: null,\n        cityId: null,\n\n        // Typing placeholder state\n        dynamicPlaceholder: '',\n        _phTexts: [],\n        _phIndex: 0,\n        _phCharIndex: 0,\n        _phTimer: null,\n        _phErasing: false,\n\n        init() {\n            const config = window.SMART_SEARCH_CONFIG || {};\n            if (!this.cityId) {\n                this.cityId = config.cityId || null;\n            }\n            // Fallback: CATALOG_NAV_CONFIG (\u0432\u0441\u0435\u0433\u0434\u0430 \u0437\u0430\u0434\u0430\u043D \u0432 base.html)\n            if (!this.cityId) {\n                const navConfig = window.CATALOG_NAV_CONFIG || {};\n                this.cityId = navConfig.cityId || null;\n            }\n\n            this._initPlaceholders();\n        },\n\n        /** \u0421\u043E\u0431\u0440\u0430\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u043E\u0432 \u0438\u0437 \u043F\u043E\u0434\u0443\u0441\u043B\u0443\u0433 \u0438 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0430\u043D\u0438\u043C\u0430\u0446\u0438\u044E */\n        _initPlaceholders() {\n            const navConfig = window.CATALOG_NAV_CONFIG || {};\n            const groups = navConfig.groupedCategories || [];\n            const names = [];\n\n            for (const g of groups) {\n                for (const cat of (g.categories || [])) {\n                    for (const sub of (cat.subservices || [])) {\n                        if (sub.name && sub.name.length <= 22) {\n                            names.push(sub.name);\n                        }\n                    }\n                }\n            }\n\n            // Fallback \u0435\u0441\u043B\u0438 \u043F\u043E\u0434\u0443\u0441\u043B\u0443\u0433 \u043D\u0435\u0442\n            if (names.length === 0) {\n                names.push(\n                    '\u0422\u0430\u0439\u0441\u043A\u0438\u0439 \u043C\u0430\u0441\u0441\u0430\u0436',\n                    'SPA-\u0441\u0430\u043B\u043E\u043D',\n                    '\u0411\u0430\u043D\u044F \u0441 \u0432\u0435\u043D\u0438\u043A\u043E\u043C',\n                    '\u041A\u0443\u0440\u0441\u044B \u043C\u0430\u0441\u0441\u0430\u0436\u0430',\n                    '\u041A\u043E\u0441\u043C\u0435\u0442\u043E\u043B\u043E\u0433',\n                    '\u041C\u0430\u043D\u0438\u043A\u044E\u0440',\n                    '\u041C\u0430\u0441\u0441\u0430\u0436 \u0441 \u0432\u044B\u0435\u0437\u0434\u043E\u043C'\n                );\n            }\n\n            // Fisher-Yates shuffle\n            for (let i = names.length - 1; i > 0; i--) {\n                const j = Math.floor(Math.random() * (i + 1));\n                [names[i], names[j]] = [names[j], names[i]];\n            }\n\n            this._phTexts = names;\n            this._phIndex = 0;\n            this._phCharIndex = 0;\n            this._phErasing = false;\n            this._phTick();\n        },\n\n        /** \u041E\u0434\u0438\u043D \u0448\u0430\u0433 \u0430\u043D\u0438\u043C\u0430\u0446\u0438\u0438: \u043F\u0435\u0447\u0430\u0442\u044C \u0438\u043B\u0438 \u0441\u0442\u0438\u0440\u0430\u043D\u0438\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u0430 */\n        _phTick() {\n            // \u041D\u0435 \u0430\u043D\u0438\u043C\u0438\u0440\u043E\u0432\u0430\u0442\u044C, \u0435\u0441\u043B\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043D\u0430\u0447\u0430\u043B \u0432\u0432\u043E\u0434\u0438\u0442\u044C \u0437\u0430\u043F\u0440\u043E\u0441\n            if (this.query.length > 0) {\n                this._phTimer = setTimeout(() => this._phTick(), 500);\n                return;\n            }\n\n            const text = this._phTexts[this._phIndex];\n            if (!text) return;\n\n            if (!this._phErasing) {\n                // \u041F\u0435\u0447\u0430\u0442\u0430\u0435\u043C\n                this._phCharIndex++;\n                this.dynamicPlaceholder = text.slice(0, this._phCharIndex);\n\n                if (this._phCharIndex >= text.length) {\n                    // \u041F\u0430\u0443\u0437\u0430 \u043F\u0435\u0440\u0435\u0434 \u0441\u0442\u0438\u0440\u0430\u043D\u0438\u0435\u043C\n                    this._phErasing = true;\n                    this._phTimer = setTimeout(() => this._phTick(), 2000);\n                    return;\n                }\n                this._phTimer = setTimeout(() => this._phTick(), 80);\n            } else {\n                // \u0421\u0442\u0438\u0440\u0430\u0435\u043C\n                this._phCharIndex--;\n                this.dynamicPlaceholder = text.slice(0, this._phCharIndex);\n\n                if (this._phCharIndex <= 0) {\n                    // \u041F\u0435\u0440\u0435\u0445\u043E\u0434\u0438\u043C \u043A \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u043C\u0443 \u0442\u0435\u043A\u0441\u0442\u0443\n                    this._phErasing = false;\n                    this._phIndex = (this._phIndex + 1) % this._phTexts.length;\n                    this._phTimer = setTimeout(() => this._phTick(), 400);\n                    return;\n                }\n                this._phTimer = setTimeout(() => this._phTick(), 40);\n            }\n        },\n\n        onInput() {\n            clearTimeout(this.debounceTimer);\n            const q = this.query.trim();\n\n            if (q.length < 2) {\n                this.suggestions = [];\n                this.noResults = false;\n                this.isOpen = false;\n                this.selectedIndex = -1;\n                return;\n            }\n\n            this.debounceTimer = setTimeout(() => {\n                this.fetchSuggestions(q);\n            }, 200);\n        },\n\n        async fetchSuggestions(q) {\n            this.loading = true;\n            try {\n                let url = '/api/smart-search/suggest/?q=' + encodeURIComponent(q);\n                if (this.cityId) {\n                    url += '&city_id=' + this.cityId;\n                }\n                const resp = await fetch(url);\n                if (!resp.ok) return;\n                const data = await resp.json();\n                this.suggestions = data;\n                this.noResults = data.length === 0;\n                this.isOpen = data.length > 0 || this.noResults;\n                this.selectedIndex = -1;\n            } catch (e) {\n                // Silently fail \u2014 autocomplete is non-critical\n            } finally {\n                this.loading = false;\n            }\n        },\n\n        onKeydown(e) {\n            if (e.key === 'Enter') {\n                e.preventDefault();\n                if (this.isOpen && this.suggestions.length > 0) {\n                    if (this.selectedIndex >= 0) {\n                        this.goTo(this.selectedIndex);\n                    } else {\n                        this.goTo(0);\n                    }\n                } else {\n                    this.submitSearch();\n                }\n                return;\n            }\n\n            if (!this.isOpen || this.suggestions.length === 0) return;\n\n            switch (e.key) {\n                case 'ArrowDown':\n                    e.preventDefault();\n                    this.selectedIndex = Math.min(\n                        this.selectedIndex + 1,\n                        this.suggestions.length - 1\n                    );\n                    break;\n                case 'ArrowUp':\n                    e.preventDefault();\n                    this.selectedIndex = Math.max(this.selectedIndex - 1, -1);\n                    break;\n                case 'Escape':\n                    this.close();\n                    break;\n            }\n        },\n\n        submitSearch() {\n            const q = this.query.trim();\n            if (q.length < 2) return;\n            window.location.href = '/search/?q=' + encodeURIComponent(q);\n        },\n\n        goTo(idx) {\n            const s = this.suggestions[idx];\n            if (s && s.url) {\n                window.location.href = s.url;\n            }\n        },\n\n        close() {\n            this.isOpen = false;\n            this.selectedIndex = -1;\n        },\n\n        /** \u0418\u043A\u043E\u043D\u043A\u0430 \u0442\u0438\u043F\u0430 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0438 */\n        typeIcon(type) {\n            switch (type) {\n                case 'category': return 'grid';\n                case 'subservice': return 'tag';\n                case 'metro': return 'train';\n                case 'attribute': return 'filter';\n                default: return 'search';\n            }\n        }\n    };\n}\nwindow.smartSearch = smartSearch;\n"],
  "mappings": "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",
  "names": ["smartSearch", "config", "navConfig", "groups", "names", "g", "cat", "sub", "j", "text", "q", "url", "resp", "data", "idx", "type"]
}
