import { useCallback, useEffect, useRef, useState } from 'react';
import { SeekoraClient } from '@seekora-ai/search-sdk';
/** Build hierarchy from doc: either nested doc.hierarchy or flat keys like doc['hierarchy.lvl0'] */
function getHierarchy(doc) {
    const hierarchy = {};
    if (doc?.hierarchy && typeof doc.hierarchy === 'object') {
        hierarchy.lvl0 = doc.hierarchy.lvl0;
        hierarchy.lvl1 = doc.hierarchy.lvl1;
        hierarchy.lvl2 = doc.hierarchy.lvl2;
        hierarchy.lvl3 = doc.hierarchy.lvl3;
        hierarchy.lvl4 = doc.hierarchy.lvl4;
        hierarchy.lvl5 = doc.hierarchy.lvl5;
    }
    else if (doc && typeof doc === 'object') {
        hierarchy.lvl0 = doc['hierarchy.lvl0'];
        hierarchy.lvl1 = doc['hierarchy.lvl1'];
        hierarchy.lvl2 = doc['hierarchy.lvl2'];
        hierarchy.lvl3 = doc['hierarchy.lvl3'];
        hierarchy.lvl4 = doc['hierarchy.lvl4'];
        hierarchy.lvl5 = doc['hierarchy.lvl5'];
    }
    return hierarchy;
}
function transformResults(results) {
    const stripMark = (s) => typeof s === 'string' ? s.replace(/<\/?mark>/g, '') : (s ? String(s) : '');
    return results.map((result) => {
        const doc = result?.document ?? result;
        const hierarchy = getHierarchy(doc);
        const url = doc.url || result.url || doc.route || result.route || doc.link || result.link || '';
        const rawTitle = doc.title || result.title || doc.name || result.name || hierarchy?.lvl3 || hierarchy?.lvl2 || hierarchy?.lvl1 || hierarchy?.lvl0 || '';
        const content = doc.content ?? result.content ?? doc.description ?? result.description ?? doc.snippet ?? result.snippet ?? '';
        const description = doc.description ?? result.description ?? (typeof content === 'string' ? content.substring(0, 150) : '');
        const plainTitle = stripMark(rawTitle) || stripMark(hierarchy?.lvl3) || stripMark(hierarchy?.lvl2) || stripMark(hierarchy?.lvl1) || stripMark(hierarchy?.lvl0) || 'Untitled';
        const plainContent = stripMark(content)?.substring(0, 200) || content;
        const apiHighlight = result?.highlight ?? doc?.highlight;
        const highlightTitle = typeof apiHighlight?.title === 'string' ? apiHighlight.title : undefined;
        const highlightContent = typeof apiHighlight?.content === 'string' ? apiHighlight.content : undefined;
        return {
            url,
            title: plainTitle,
            content: plainContent,
            description: stripMark(description) || description,
            category: doc.category ?? result.category ?? hierarchy?.lvl0 ?? '',
            hierarchy,
            route: doc.route ?? result.route,
            parentTitle: doc.parent_title ?? doc.parentTitle ?? result.parent_title ?? result.parentTitle,
            type: doc.type ?? result.type ?? '',
            anchor: doc.anchor ?? result.anchor ?? '',
            _source: 'seekora',
            highlight: (highlightTitle ?? highlightContent) ? { title: highlightTitle, content: highlightContent } : undefined,
        };
    });
}
export function useSeekoraSearch(options) {
    const { storeId, storeSecret, apiEndpoint, maxResults = 20, debounceMs = 200, analyticsTags = ['docsearch'], groupField = 'hierarchy.lvl3', groupSize = 10, } = options;
    const [query, setQueryState] = useState('');
    const [suggestions, setSuggestions] = useState([]);
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState(null);
    const [selectedIndex, setSelectedIndex] = useState(0);
    const clientRef = useRef(null);
    const lastSearchContextRef = useRef(null);
    const debounceTimerRef = useRef(null);
    const abortControllerRef = useRef(null);
    useEffect(() => {
        if (!storeId)
            return;
        const config = {
            storeId,
            readSecret: storeSecret,
            logLevel: 'warn',
            enableContextCollection: true,
            enableEventQueue: true, // Enable batching for better performance
            eventQueue: {
                batchSize: 10,
                flushInterval: 5000, // 5 seconds
                enablePersistence: true,
            },
        };
        if (apiEndpoint) {
            if (['local', 'stage', 'production'].includes(apiEndpoint)) {
                config.environment = apiEndpoint;
            }
            else {
                // Search SDK path is /v1/search; backend serves at /api/v1/search. baseUrl must include /api.
                const base = apiEndpoint.replace(/\/$/, '');
                config.baseUrl = base.endsWith('/api') ? base : `${base}/api`;
            }
        }
        try {
            clientRef.current = new SeekoraClient(config);
        }
        catch (err) {
            console.error('Failed to initialize SeekoraClient:', err);
            setError('Failed to initialize search client');
        }
        return () => {
            clientRef.current = null;
        };
    }, [storeId, storeSecret, apiEndpoint]);
    const performSearch = useCallback(async (searchQuery) => {
        if (!clientRef.current) {
            setError('Search client not initialized');
            return;
        }
        if (!searchQuery.trim()) {
            setSuggestions([]);
            return;
        }
        if (abortControllerRef.current)
            abortControllerRef.current.abort();
        abortControllerRef.current = new AbortController();
        setIsLoading(true);
        setError(null);
        try {
            const response = await clientRef.current.search(searchQuery, {
                per_page: maxResults,
                analytics_tags: analyticsTags,
                return_fields: [
                    'hierarchy.lvl0', 'hierarchy.lvl1', 'hierarchy.lvl2', 'hierarchy.lvl3',
                    'hierarchy.lvl4', 'hierarchy.lvl5', 'hierarchy.lvl6',
                    'content', 'type', 'url', 'title', 'anchor'
                ],
                snippet_fields: [
                    'hierarchy.lvl1', 'hierarchy.lvl2', 'hierarchy.lvl3',
                    'hierarchy.lvl4', 'hierarchy.lvl5', 'hierarchy.lvl6', 'content'
                ],
                snippet_prefix: '<mark>',
                snippet_suffix: '</mark>',
                include_snippets: true,
                group_field: groupField,
                group_size: groupSize,
            });
            if (abortControllerRef.current?.signal.aborted)
                return;
            if (response?.context)
                lastSearchContextRef.current = response.context;
            setSuggestions(transformResults(response.results || []));
            setSelectedIndex(0);
        }
        catch (err) {
            if (err instanceof Error && err.name === 'AbortError')
                return;
            console.error('Search failed:', err);
            setError(err instanceof Error ? err.message : 'Search failed');
            setSuggestions([]);
        }
        finally {
            setIsLoading(false);
        }
    }, [maxResults, analyticsTags, groupField, groupSize]);
    const setQuery = useCallback((newQuery) => {
        setQueryState(newQuery);
        setSelectedIndex(0);
        if (debounceTimerRef.current)
            clearTimeout(debounceTimerRef.current);
        debounceTimerRef.current = setTimeout(() => performSearch(newQuery), debounceMs);
    }, [performSearch, debounceMs]);
    const selectNext = useCallback(() => {
        setSelectedIndex((prev) => (prev >= suggestions.length - 1 ? 0 : prev + 1));
    }, [suggestions.length]);
    const selectPrev = useCallback(() => {
        setSelectedIndex((prev) => (prev <= 0 ? suggestions.length - 1 : prev - 1));
    }, [suggestions.length]);
    const reset = useCallback(() => {
        if (abortControllerRef.current)
            abortControllerRef.current.abort();
        if (debounceTimerRef.current)
            clearTimeout(debounceTimerRef.current);
        setQueryState('');
        setSuggestions([]);
        setIsLoading(false);
        setError(null);
        setSelectedIndex(0);
    }, []);
    const getSelectedItem = useCallback(() => {
        return suggestions[selectedIndex] || null;
    }, [suggestions, selectedIndex]);
    const trackDocClick = useCallback((hit, position) => {
        const client = clientRef.current;
        if (!client?.trackEvent)
            return;
        const context = lastSearchContextRef.current ?? undefined;
        const itemId = hit.url || hit.id || hit.title || String(position);
        client.trackEvent({
            event_name: 'doc_click',
            clicked_item_id: itemId,
            metadata: { position, result: hit, source: 'docsearch' },
        }, context);
    }, []);
    useEffect(() => {
        return () => {
            if (abortControllerRef.current)
                abortControllerRef.current.abort();
            if (debounceTimerRef.current)
                clearTimeout(debounceTimerRef.current);
        };
    }, []);
    return {
        query,
        suggestions,
        isLoading,
        error,
        selectedIndex,
        setQuery,
        selectNext,
        selectPrev,
        setSelectedIndex,
        reset,
        getSelectedItem,
        trackDocClick,
    };
}
