/**
 * Enhanced Query Suggestions Hook
 *
 * Provides full support for query suggestions API including:
 * - Basic suggestions
 * - Dropdown recommendations (trending, top searches, related)
 * - Filtered tabs with products
 * - Recent searches (local storage)
 * - Analytics tracking
 */
import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { log } from '@seekora-ai/ui-sdk-core';
// ============================================================================
// Local Storage Helpers
// ============================================================================
const RECENT_SEARCHES_DEFAULT_KEY = 'seekora_recent_searches';
const MAX_RECENT_SEARCHES_DEFAULT = 10;
function getRecentSearchesFromStorage(key) {
    if (typeof window === 'undefined')
        return [];
    try {
        const stored = localStorage.getItem(key);
        if (!stored)
            return [];
        return JSON.parse(stored);
    }
    catch {
        return [];
    }
}
function saveRecentSearchesToStorage(key, searches) {
    if (typeof window === 'undefined')
        return;
    try {
        localStorage.setItem(key, JSON.stringify(searches));
    }
    catch (error) {
        log.warn('Failed to save recent searches to localStorage', { error });
    }
}
// ============================================================================
// Transform API Response
// ============================================================================
function transformSuggestion(raw) {
    const query = raw.query || raw.text || String(raw);
    const highlighted = raw._highlightResult?.query?.value;
    return {
        query,
        popularity: raw.popularity,
        count: raw.instant_search?.exact_nb_hits ?? raw.popularity ?? raw.count,
        objectID: raw.objectID,
        highlightedQuery: highlighted ? parseHighlight(highlighted) : undefined,
        categories: raw.categories?.map((c) => ({
            value: c.value || c.name,
            count: c.count,
            path: c.path,
        })),
        facets: raw.instant_search?.facets || raw.facets,
        metadata: raw,
    };
}
function parseHighlight(highlighted) {
    // Convert __ais-highlight__ markers to HTML
    return highlighted
        .replace(/__ais-highlight__/g, '<mark>')
        .replace(/__\/ais-highlight__/g, '</mark>');
}
function transformProduct(raw) {
    const meta = raw.metadata || {};
    return {
        id: raw.id || raw.objectID,
        objectID: raw.objectID || raw.id,
        title: raw.title || raw.name || raw.productName || meta.name || meta.productName || '',
        name: raw.name || raw.title || meta.name || meta.productName || '',
        image: raw.image || raw.imageUrl || meta.image || meta.image_url || meta.images?.[0] || '',
        price: raw.price ?? raw.sellPrice ?? meta.sellPrice ?? meta.price,
        currency: raw.currency || meta.currency || '',
        url: raw.url || raw.productId || meta.url || meta.productId || '',
        clicks: raw.clicks,
        conversions: raw.conversions,
        revenue: raw.revenue,
        trend_score: raw.trend_score,
        metadata: raw.metadata || raw,
    };
}
function transformFilteredTab(raw) {
    return {
        id: raw.id,
        label: raw.label,
        filter: raw.filter,
        products: raw.products?.map(transformProduct) || [],
        nb_hits: raw.nb_hits,
        processing_time_ms: raw.processing_time_ms,
    };
}
// ============================================================================
// Main Hook
// ============================================================================
export function useQuerySuggestionsEnhanced(options) {
    const { client, query, enabled = true, prefetch = false, debounceMs = 200, maxSuggestions = 10, minQueryLength = 1, includeDropdownRecommendations = false, includeDropdownProductList = true, includeFilteredTabs = true, includeCategories = true, includeFacets = true, // CHANGED: Enable facets by default
    maxCategories = 3, maxFacets = 5, filteredTabs, minPopularity, timeRange, disableTypoTolerance, analyticsTags, enableRecentSearches = true, maxRecentSearches = MAX_RECENT_SEARCHES_DEFAULT, recentSearchesKey = RECENT_SEARCHES_DEFAULT_KEY, onSuggestionsLoaded, onError, } = options;
    // State
    const [suggestions, setSuggestions] = useState([]);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    const [dropdownRecommendations, setDropdownRecommendations] = useState(null);
    const [recentSearches, setRecentSearches] = useState([]);
    const [processingTimeMs, setProcessingTimeMs] = useState(null);
    const [totalHits, setTotalHits] = useState(0);
    const [currentPage, setCurrentPage] = useState(0);
    const [totalPages, setTotalPages] = useState(0);
    const [originalQuery, setOriginalQuery] = useState('');
    // Refs
    const debounceTimerRef = useRef(null);
    const abortControllerRef = useRef(null);
    const mountedRef = useRef(true);
    // Load recent searches on mount
    useEffect(() => {
        if (enableRecentSearches) {
            const stored = getRecentSearchesFromStorage(recentSearchesKey);
            setRecentSearches(stored.slice(0, maxRecentSearches));
        }
        return () => {
            mountedRef.current = false;
        };
    }, [enableRecentSearches, recentSearchesKey, maxRecentSearches]);
    // Fetch suggestions
    const fetchSuggestions = useCallback(async (searchQuery) => {
        if (!client)
            return;
        // When minQueryLength is 0, allow empty query so overlay can show default/trending recommendations on open
        if (!searchQuery.trim() && minQueryLength > 0) {
            setSuggestions([]);
            setDropdownRecommendations(null);
            return;
        }
        // Cancel previous request
        if (abortControllerRef.current) {
            abortControllerRef.current.abort();
        }
        abortControllerRef.current = new AbortController();
        setLoading(true);
        setError(null);
        try {
            const response = await client.getSuggestions?.(searchQuery, {
                hitsPerPage: maxSuggestions,
                include_dropdown_recommendations: includeDropdownRecommendations || (filteredTabs && filteredTabs.length > 0),
                include_dropdown_product_list: includeDropdownProductList,
                include_filtered_tabs: includeFilteredTabs,
                include_categories: includeCategories,
                include_facets: includeFacets,
                max_categories: maxCategories,
                max_facets: maxFacets,
                filtered_tabs: filteredTabs,
                min_popularity: minPopularity,
                time_range: timeRange,
                disable_typo_tolerance: disableTypoTolerance,
                analytics_tags: analyticsTags,
                returnFullResponse: true,
            });
            if (!mountedRef.current)
                return;
            // Transform suggestions
            const rawSuggestions = response.suggestions || [];
            const transformedSuggestions = rawSuggestions.map(transformSuggestion);
            setSuggestions(transformedSuggestions);
            // Extract dropdown recommendations from extensions
            const extensions = (response.extensions || {});
            const rawResults = response.results;
            const secondResultHits = Array.isArray(rawResults?.[1]?.hits) ? rawResults[1].hits : [];
            // Multi-index response: results[0]=suggestions, results[1]=product hits; expose results[1].hits as product_hits for fallback when extensions have no products
            const productHits = secondResultHits.length > 0 ? secondResultHits.map((h) => transformProduct(h)) : [];
            const recommendations = {
                trending_searches: Array.isArray(extensions.trending_searches) ? extensions.trending_searches : [],
                top_searches: Array.isArray(extensions.top_searches) ? extensions.top_searches : [],
                related_searches: Array.isArray(extensions.related_searches) ? extensions.related_searches : [],
                trending_products: Array.isArray(extensions.trending_products) ? extensions.trending_products.map(transformProduct) : [],
                item_recommendations: Array.isArray(extensions.item_recommendations) ? extensions.item_recommendations.map(transformProduct) : [],
                product_hits: productHits.length > 0 ? productHits : undefined,
                popular_brands: Array.isArray(extensions.popular_brands) ? extensions.popular_brands : [],
                filtered_tabs: Array.isArray(extensions.filtered_tabs) ? extensions.filtered_tabs.map(transformFilteredTab) : [],
                processing_time_ms: typeof extensions.processing_time_ms === 'number' ? extensions.processing_time_ms : undefined,
                cached_at: typeof extensions.cached_at === 'string' ? extensions.cached_at : undefined,
            };
            setDropdownRecommendations(recommendations);
            // Extract metadata from raw response
            const raw = response.raw;
            const rawResultsArr = raw?.results;
            const rawResult = (rawResultsArr?.[0] ?? raw ?? {});
            const num = (v) => (typeof v === 'number' && !Number.isNaN(v) ? v : 0);
            const str = (v) => (typeof v === 'string' ? v : '');
            setProcessingTimeMs(typeof rawResult.processingTimeMS === 'number' ? rawResult.processingTimeMS : null);
            setTotalHits(num(rawResult.nbHits) || transformedSuggestions.length);
            setCurrentPage(num(rawResult.page) || 0);
            setTotalPages(num(rawResult.nbPages) || 1);
            setOriginalQuery(str(rawResult.query) || searchQuery);
            // Callback
            if (onSuggestionsLoaded) {
                onSuggestionsLoaded({
                    suggestions: transformedSuggestions,
                    nbHits: num(rawResult.nbHits) || transformedSuggestions.length,
                    page: num(rawResult.page) || 0,
                    nbPages: num(rawResult.nbPages) || 1,
                    hitsPerPage: num(rawResult.hitsPerPage) || maxSuggestions,
                    processingTimeMS: typeof rawResult.processingTimeMS === 'number' ? rawResult.processingTimeMS : undefined,
                    query: str(rawResult.query) || searchQuery,
                    dropdownRecommendations: recommendations,
                    results: Array.isArray(response.results) ? response.results : undefined,
                    extensions,
                });
            }
            log.verbose('Query suggestions loaded', {
                query: searchQuery,
                suggestionsCount: transformedSuggestions.length,
                hasRecommendations: Object.keys(recommendations).some(k => Array.isArray(recommendations[k]) && recommendations[k].length > 0),
            });
        }
        catch (err) {
            if (!mountedRef.current)
                return;
            const error = err instanceof Error ? err : new Error(String(err));
            if (error.name === 'AbortError')
                return;
            // Check if it's a 404 error (suggestions not enabled for this store).
            // The search SDK wraps axios errors into plain Error objects with the status
            // embedded in the message, e.g. "[getSuggestions] ... (404)".
            const errMsg = error.message || '';
            const is404 = err?.response?.status === 404 ||
                err?.status === 404 ||
                /\(404\)/.test(errMsg);
            if (is404) {
                // Silently handle 404 - suggestions feature not enabled
                log.verbose('Query suggestions not enabled for this store (404)');
                setSuggestions([]);
                setDropdownRecommendations(null);
                setError(null);
            }
            else {
                // For other errors, log and set error state
                log.error('Failed to fetch query suggestions', { query: searchQuery, error: error.message });
                setError(error);
                setSuggestions([]);
                setDropdownRecommendations(null);
                if (onError) {
                    onError(error);
                }
            }
        }
        finally {
            if (mountedRef.current) {
                setLoading(false);
            }
        }
    }, [
        client,
        minQueryLength,
        maxSuggestions,
        includeDropdownRecommendations,
        includeDropdownProductList,
        includeFilteredTabs,
        includeCategories,
        includeFacets,
        maxCategories,
        maxFacets,
        filteredTabs,
        minPopularity,
        timeRange,
        disableTypoTolerance,
        analyticsTags,
        onSuggestionsLoaded,
        onError,
    ]);
    // Prefetch: fire initial empty-query fetch once client is ready (before dropdown opens)
    const prefetchedRef = useRef(false);
    useEffect(() => {
        if (!prefetch || prefetchedRef.current)
            return;
        if (minQueryLength > 0)
            return;
        if (!client?.getSuggestions)
            return;
        prefetchedRef.current = true;
        fetchSuggestions('');
    }, [prefetch, client, minQueryLength, fetchSuggestions]);
    // Debounced fetch effect
    useEffect(() => {
        if (debounceTimerRef.current) {
            clearTimeout(debounceTimerRef.current);
        }
        if (!enabled || query.length < minQueryLength) {
            // Don't clear prefetched data when dropdown is closed
            if (prefetch && prefetchedRef.current && query === '') {
                // Keep prefetched data intact
                setLoading(false);
                setError(null);
                return;
            }
            setSuggestions([]);
            setDropdownRecommendations(null);
            setLoading(false);
            setError(null);
            return;
        }
        // When dropdown opens with empty query and we already have prefetched data, skip re-fetch
        if (prefetch && prefetchedRef.current && query === '') {
            return;
        }
        setLoading(true);
        debounceTimerRef.current = setTimeout(() => {
            fetchSuggestions(query);
        }, debounceMs);
        return () => {
            if (debounceTimerRef.current) {
                clearTimeout(debounceTimerRef.current);
            }
        };
    }, [query, enabled, prefetch, minQueryLength, debounceMs, fetchSuggestions]);
    // Recent search management
    const addRecentSearch = useCallback((searchQuery, resultsCount) => {
        if (!enableRecentSearches || !searchQuery.trim())
            return;
        setRecentSearches(prev => {
            // Remove existing entry for same query
            const filtered = prev.filter(s => s.query.toLowerCase() !== searchQuery.toLowerCase());
            // Add new entry at the beginning
            const newSearch = {
                query: searchQuery.trim(),
                timestamp: Date.now(),
                resultsCount,
            };
            const updated = [newSearch, ...filtered].slice(0, maxRecentSearches);
            saveRecentSearchesToStorage(recentSearchesKey, updated);
            return updated;
        });
    }, [enableRecentSearches, maxRecentSearches, recentSearchesKey]);
    const removeRecentSearch = useCallback((searchQuery) => {
        setRecentSearches(prev => {
            const updated = prev.filter(s => s.query !== searchQuery);
            saveRecentSearchesToStorage(recentSearchesKey, updated);
            return updated;
        });
    }, [recentSearchesKey]);
    const clearRecentSearches = useCallback(() => {
        setRecentSearches([]);
        saveRecentSearchesToStorage(recentSearchesKey, []);
    }, [recentSearchesKey]);
    // Manual refetch
    const refetch = useCallback(async () => {
        if (query.length >= minQueryLength) {
            await fetchSuggestions(query);
        }
    }, [query, minQueryLength, fetchSuggestions]);
    // Derived values
    const trendingSearches = dropdownRecommendations?.trending_searches || [];
    const topSearches = dropdownRecommendations?.top_searches || [];
    const relatedSearches = dropdownRecommendations?.related_searches || [];
    const popularBrands = dropdownRecommendations?.popular_brands || [];
    const filteredTabsResult = dropdownRecommendations?.filtered_tabs || [];
    // Use trending_products, then item_recommendations, then first filtered_tab's products, then results[1].hits (product_hits) so grid shows for any API shape
    const trendingProducts = useMemo(() => {
        const fromTrending = dropdownRecommendations?.trending_products;
        if (fromTrending && fromTrending.length > 0)
            return fromTrending;
        const fromItemRecs = dropdownRecommendations?.item_recommendations;
        if (fromItemRecs && fromItemRecs.length > 0)
            return fromItemRecs;
        const firstTab = dropdownRecommendations?.filtered_tabs?.[0];
        if (firstTab?.products && firstTab.products.length > 0)
            return firstTab.products;
        return dropdownRecommendations?.product_hits ?? [];
    }, [dropdownRecommendations?.trending_products, dropdownRecommendations?.item_recommendations, dropdownRecommendations?.filtered_tabs, dropdownRecommendations?.product_hits]);
    const hasContent = useMemo(() => {
        return (suggestions.length > 0 ||
            recentSearches.length > 0 ||
            trendingSearches.length > 0 ||
            topSearches.length > 0 ||
            relatedSearches.length > 0 ||
            popularBrands.length > 0 ||
            filteredTabsResult.length > 0 ||
            trendingProducts.length > 0);
    }, [
        suggestions,
        recentSearches,
        trendingSearches,
        topSearches,
        relatedSearches,
        popularBrands,
        filteredTabsResult,
        trendingProducts,
    ]);
    // Get all navigable items for keyboard navigation
    const getAllNavigableItems = useCallback(() => {
        const items = [];
        let index = 0;
        // Recent searches first (when query is empty)
        if (query.length === 0 && recentSearches.length > 0) {
            recentSearches.forEach(search => {
                items.push({ type: 'recent', index: index++, data: search });
            });
        }
        // Suggestions
        suggestions.forEach(suggestion => {
            items.push({ type: 'suggestion', index: index++, data: suggestion });
        });
        // Trending searches
        trendingSearches.forEach(trending => {
            items.push({ type: 'trending', index: index++, data: trending });
        });
        // Products
        trendingProducts.forEach(product => {
            items.push({ type: 'product', index: index++, data: product });
        });
        // Brands
        popularBrands.forEach(brand => {
            items.push({ type: 'brand', index: index++, data: brand });
        });
        return items;
    }, [query, recentSearches, suggestions, trendingSearches, trendingProducts, popularBrands]);
    return {
        suggestions,
        loading,
        error,
        dropdownRecommendations,
        trendingSearches,
        topSearches,
        relatedSearches,
        popularBrands,
        filteredTabs: filteredTabsResult,
        trendingProducts,
        recentSearches,
        processingTimeMs,
        totalHits,
        currentPage,
        totalPages,
        originalQuery,
        addRecentSearch,
        removeRecentSearch,
        clearRecentSearches,
        refetch,
        hasContent,
        getAllNavigableItems,
    };
}
export default useQuerySuggestionsEnhanced;
