document.addEventListener("alpine:init", () => {
    Alpine.store('fastFuzzySearchPanel', {
        isVisible: false,
        prefix: '',
        query: '',
        loading: true,
        hasDispatched: false,

        toggle() {
            this.isVisible = !this.isVisible
        },

        show() {
            this.isVisible = true
        },

        hide() {
            this.prefix = '';
            this.query = '';
            this.isVisible = false
        },
    });

    Alpine.effect(() => {
        const store = Alpine.store('fastFuzzySearchPanel');
        if (!store.loading && !store.hasDispatched) {
            window.dispatchEvent(new CustomEvent('fast-fuzzy-search:loaded'));
            store.hasDispatched = true;
        }
    });

    let haystack = [];
    let data = [];

    Alpine.data("fastFuzzySearchPanel", () => ({
        userInput: '',
        resultsVisible: false,
        searchResults: [],
        activeResultIndex: 0,
        selected: null,
        items: [],
        showAll: false,
        excludedPostTypes: Alpine.$persist([]),
        selectedPostType: null,
        fuzzy: new uFuzzy({
            intraMode: 1,
            unicode: true,
            interSplit: "[^\\p{L}\\d']+",
            intraSplit: "\\p{Ll}\\p{Lu}",
            intraBound: "\\p{L}\\d|\\d\\p{L}|\\p{Ll}\\p{Lu}",
            intraChars: "[\\p{L}\\d']",
            intraContr: "'\\p{L}{1,2}\\b",
        }),
        scrolled: false,
        lastScroll: 0,

        async init() {
            if (FastFuzzySearch?.options?.hide_on_scroll === '1') {
                window.addEventListener('scroll', ffs_throttle(this.handleScroll.bind(this), 100));
            }

            this.activeResultIndex = 0;

            this.$store.fastFuzzySearchPanel.loading = true;

            await this.fetchData();

            this.$store.fastFuzzySearchPanel.loading = false;

            // Show initial 6 items for overlay mode (button/icon-button/input-button triggers)
            if (this.$root?.classList.contains('fast-fuzzy-search--inline') && haystack.length > 0) {
                this.resultsVisible = true;
                this.items = data.slice(0, 6);
                this.searchResults = haystack.slice(0, 6);
                this.activeResultIndex = 0;
            }

            this.$watch('activeResultIndex', () => {
                this.$root.querySelector(`#search-results a[data-index="${this.activeResultIndex}"]`)?.scrollIntoView({
                    behavior: 'smooth',
                    block: 'end',
                    inline: 'nearest',
                });
            });
        },

        get query() {
            return Alpine.store('fastFuzzySearchPanel').prefix ? `${Alpine.store('fastFuzzySearchPanel').prefix} ${this.userInput}` : this.userInput;
        },

        async fetchData() {
            try {
                // Use REST API endpoint (cache-plugin friendly, no nonce needed)
                const restUrl = FastFuzzySearch.rest_url || (FastFuzzySearch.homeURL?.replace(/\/+$/, '') + '/wp-json/fast-fuzzy-search/v1/search');
                const url = new URL(restUrl);
                url.searchParams.set('_', Date.now());

                const response = await fetch(url.toString(), {
                    method: 'POST',
                    headers: {
                        'Accept': 'application/json',
                    },
                });

                if (response.ok) {
                    const json = await response.json();

                    haystack = json.haystack;
                    data = json.data;

                    this.searchDebounced();
                }

            } catch (error) {
                console.error('Fast Fuzzy Search: failed to fetch search index. Falling back to admin-ajax.php', error);

                // Fallback to admin-ajax.php if REST endpoint fails
                try {
                    const fallback = await fetch(FastFuzzySearch.ajax_url, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded',
                        },
                        body: new URLSearchParams({
                            action: FastFuzzySearch.ajax_action,
                            security: FastFuzzySearch._wpnonce,
                        }),
                    });

                    if (fallback.ok) {
                        const json = await fallback.json();
                        haystack = json.haystack;
                        data = json.data;
                        this.searchDebounced();
                    }
                } catch (fallbackError) {
                    console.error('Fast Fuzzy Search: fallback also failed.', fallbackError);
                }
            }
        },

        handleScroll(event) {
            if (FastFuzzySearch.options.type !== 'input-field') {
                return;
            }

            if (this.$root.classList.contains('fast-fuzzy-search--inline')) {
                return;
            }

            // Get current vertical scroll position.
            const currentScroll = window.pageYOffset || document.documentElement.scrollTop;

            // Check if we scrolled down more than a threshold (e.g., 100px)
            if (currentScroll > this.lastScroll && currentScroll > 100) {
                // Scrolling down – hide the header.
                this.scrolled = true;
            } else if (currentScroll < this.lastScroll) {
                // Scrolling up – show the header.
                this.scrolled = false;
            }

            // Update the last scroll position, ensuring it doesn't go below 0.
            this.lastScroll = currentScroll <= 0 ? 0 : currentScroll;

            if (this.scrolled) {
                this.$root.classList.add('fast-fuzzy-search--scrolled');
            } else {
                this.$root.classList.remove('fast-fuzzy-search--scrolled');
            }
        },

        handleInput(event) {
            this.userInput = event.target.value;
            this.showAll = false;
            this.searchDebounced();
        },

        searchDebounced() {
            if (!this.fuzzy) {
                return;
            }

            if (this.query.length < 1) {
                this.resultsVisible = false;
                this.searchResults = [];
                this.items = [];
                return;
            }

            this.resultsVisible = true;

            let indexes = this.fuzzy.filter(haystack, this.query);

            if (indexes) {
                let resultData = indexes?.map((idx) => {
                    return {...data[idx], originalIndex: idx};
                }).filter((item) => {
                    if (!this.selectedPostType) {
                        return true;
                    }

                    return item.type && item.type.length > 0 && item.type === this.selectedPostType;
                });

                this.items = resultData;
                this.searchResults = resultData.map((item) => haystack[item.originalIndex]);
                this.showAll = false;
                this.activeResultIndex = 0;
            };
        },

        selectResult() {
            const anchors = this.$root.querySelectorAll('#search-results > li > a');
            const anchor = anchors[this.activeResultIndex];

            if (!anchor) {
                return;
            }

            anchor.click();

            this.selected = this.searchResults[this.activeResultIndex];

            this.$store.fastFuzzySearchPanel.hide();
        },

        handleArrowNavigation(event) {
            const visibleCount = this.showAll
                ? this.items.length
                : Math.min(6, this.items.length);

            if (visibleCount < 1) {
                return;
            }

            if (event.key === 'ArrowDown') {
                event.preventDefault();

                if (this.activeResultIndex < visibleCount - 1) {
                    this.activeResultIndex++;
                } else {
                    this.activeResultIndex = 0;
                }
            } else if (event.key === 'ArrowUp') {
                event.preventDefault();

                this.activeResultIndex--;

                if (this.activeResultIndex < 0) {
                    this.activeResultIndex = visibleCount - 1;
                }
            }

            const target = this.$root?.querySelector(`.fast-fuzzy-search__results li[data-index="${this.activeResultIndex}"]`);
            if (target) {
                target.scrollIntoView({
                    behavior: 'smooth',
                    block: 'center',
                    inline: 'nearest',
                });
            }
        },

        show() {
            this.$store.fastFuzzySearchPanel.show();
        },

        hide() {
            this.$store.fastFuzzySearchPanel.hide();
        },

        isActive(index) {
            if (index > -1) {
                return index === this.activeResultIndex;
            } else {
                return parseInt(this.$el.closest('li').dataset.index) === this.activeResultIndex
            }
        },

        selectResultWithEnter() {
            const activeResult = this.searchResults[this.activeResultIndex];
            if (activeResult) {
                this.selectResult(activeResult);
                this.activeResultIndex = -1;
            } else {
                this.$refs.form.submit();
            }
        },

        excludePostType(type) {
            if (this.excludedPostTypes.includes(type)) {
                this.excludedPostTypes = this.excludedPostTypes.filter((t) => t !== type);
            } else {
                this.excludedPostTypes.push(type);
            }
        },

        get prefix() {
            return this.$store.fastFuzzySearchPanel.prefix;
        },

        get hasQuery() {
            return this.userInput.length > 1
        },

        get hasPrefix() {
            return this.$store.fastFuzzySearchPanel.prefix.length > 0
        },

        get doesNotHavePrefix() {
            return this.$store.fastFuzzySearchPanel.prefix.length < 1
        },

        get hasQueryAndPrefix() {
            return this.userInput.length > 1 && this.$store.fastFuzzySearchPanel.prefix.length > 0
        },

        get hasQueryOrPrefix() {
            return this.userInput.length > 1 || this.$store.fastFuzzySearchPanel.prefix.length > 0
        },

        get shouldShowContext() {
            return this.$store.fastFuzzySearchPanel.prefix.length > 0 && this.shouldShowResults
        },

        handleXClick() {
            this.userInput = '';
            this.$refs.searchInput.value = '';
            this.$refs.searchInput.focus();
        },

        get totalResults() {
            return this.searchResults.length;
        },

        get viewAllText() {
            return 'View all ' + this.totalResults + ' results';
        },

        get hasMoreResults() {
            return this.totalResults > 6;
        },

        get displayedItems() {
            return this.showAll ? this.items : this.items.slice(0, 6);
        },

        showAllResults() {
            this.showAll = true;
            this.activeResultIndex = 0;
        },

        isLoading() {
            return this.$store.fastFuzzySearchPanel.loading;
        },

        isNotLoading() {
            return !this.$store.fastFuzzySearchPanel.loading;
        },

        isNotExcluded() {
            return !this.excludedPostTypes?.includes(this.$el.dataset.type)
        },

        isPostTypeSelected() {
            return this.selectedPostType === this.$el.closest('li').dataset.type;
        },

        isPostTypeNotSelected() {
            return !this.selectedPostType;
        },

        hasExcludedPostTypes() {
            return this.excludedPostTypes?.length > 0
        },

        handlePostTypeButtonClick() {
            const type = this.$el.closest('li').dataset.type;

            if (!type) {
                this.selectedPostType = null;
                this.searchDebounced();
                return;
            };

            this.selectedPostType = this.$el.closest('li').dataset.type;
            this.searchDebounced();
        },

        handlePostTypePlusClick() {
            this.excludedPostTypes = [];
            this.searchDebounced();
        },

        get shouldShowResults() {
            return this.resultsVisible && this.items.length > 0
        },

        get shouldShowViewAll() {
            return this.hasMoreResults && !this.showAll && this.shouldShowResults;
        },

        get isEmpty() {
            return this.resultsVisible && this.items.length < 1 && !this.hasQueryOrPrefix;
        },

        get noResults() {
            return this.resultsVisible && this.items.length < 1 && this.hasQueryOrPrefix && !this.$store.fastFuzzySearchPanel.loading;
        },

        linkActiveClass() {
            return this.isActive(parseInt(this.$el.closest('li').dataset.index)) ? 'bg-gray-100' : 'bg-gray-0';
        },

        get isHashLink() {
            const index = parseInt(this.$el.closest('li')?.dataset?.index);
            const path = this.items[index]?.path;
            return path ? path.includes('#') : false;
        },

        get isNormalLink() {
            const index = parseInt(this.$el.closest('li')?.dataset?.index);
            const path = this.items[index]?.path;
            return path ? !path.includes('#') : false;
        },

        get featuredImage() {
            const index = parseInt(this.$el?.dataset?.index);
            const image = this.items[index]?.featured_image;
            const type = this.items[index]?.type || '';

            if (image && image.length > 0) {
                return image + '?type=' + type;
            }

            return null;
        },

        get permalink() {
            const index = parseInt(this.$el.closest('li')?.dataset?.index);
            const path = this.items[index]?.path;

            if (path && path.length > 0) {
                return path;
            }

            return null;
        },

        get noFeaturedImage() {
            const index = parseInt(this.$el.closest('li')?.dataset?.index);
            const image = this.items[index]?.featured_image;

            if (!image || image.length < 1) {
                return true;
            };

            return false;
        },

        get primaryInfo() {
            const index = parseInt(this.$el.closest('li')?.dataset?.index);
            const title = this.items[index]?.title;

            if (title && title.length > 0) {
                return title;
            }

            return null;
        },

        get secondaryInfo() {
            const index = parseInt(this.$el.closest('li')?.dataset?.index);
            const price = this.items[index]?.price;

            if (price && price.length > 0) {
                return price;
            };

            const parentItems = this.searchResults[index]?.split(' / ');

            parentItems?.pop();

            return parentItems?.length > 1 ? parentItems?.join(' / ') : null;
        },

        get itemLabel() {
            const index = parseInt(this.$el.closest('li')?.dataset?.index);
            const label = this.items[index]?.type_label;

            if (label && label.length > 0) {
                return label;
            };

            return null;
        },
    }));

    Alpine.data("fastFuzzySearchIconButton", () => ({
        init() {
            if (FastFuzzySearch?.options?.hide_on_scroll === '1') {
                window.addEventListener('scroll', ffs_throttle(this.handleScroll.bind(this), 100));
            }
        },

        handleButtonClick() {
            this.$store.fastFuzzySearchPanel.show();
        },

        hide() {
            this.$store.fastFuzzySearchPanel.hide();
        },

        isNotVisible() {
            return !this.$store.fastFuzzySearchPanel.isVisible;
        },

        handleScroll(event) {
            if (this.$root.classList.contains('fast-fuzzy-search--inline')) {
                return;
            }

            // Get current vertical scroll position.
            const currentScroll = window.pageYOffset || document.documentElement.scrollTop;

            // Check if we scrolled down more than a threshold (e.g., 100px)
            if (currentScroll > this.lastScroll && currentScroll > 100) {
                // Scrolling down – hide the header.
                this.scrolled = true;
            } else if (currentScroll < this.lastScroll) {
                // Scrolling up – show the header.
                this.scrolled = false;
            }

            // Update the last scroll position, ensuring it doesn't go below 0.
            this.lastScroll = currentScroll <= 0 ? 0 : currentScroll;

            if (this.scrolled) {
                this.$root.classList.add('fast-fuzzy-search--scrolled');
            } else {
                this.$root.classList.remove('fast-fuzzy-search--scrolled');
            }
        },
    }));

    Alpine.data("fastFuzzySearchOverlayPanel", () => ({
        isVisible() {
            return this.$store.fastFuzzySearchPanel.isVisible;
        },

        handleCloseButtonClick() {
            this.$store.fastFuzzySearchPanel.hide();
        },

        hide() {
            this.$store.fastFuzzySearchPanel.hide();
        },
    }));

    Alpine.data("fastFuzzySearchTrigger", () => ({
        get loading() {
            return Alpine.store('fastFuzzySearchPanel').loading;
        },

        showSearch() {
            if (this.$el.dataset.context?.length > 0) {
                Alpine.store('fastFuzzySearchPanel').prefix = this.$el.dataset.context;
            }

            Alpine.store('fastFuzzySearchPanel').show();
        },

        get isDisabled() {
            return this.loading ? 'disabled' : false;
        },

        get isLoading() {
            return this.loading;
        },

        get isNotLoading() {
            return !this.loading;
        }
    }));
});


const ffs_throttle = (func, delay) => {
    let lastCall = 0;
    return (...args) => {
        const now = Date.now();
        if (now - lastCall >= delay) {
            lastCall = now;
            func(...args);
        }
    };
};