/**
 * InfiniteHits Component
 *
 * Displays search results with infinite scroll or "Show More" button
 * Accumulates results as user loads more pages
 */
import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { useSearchContext } from './SearchProvider';
import { useSearchState } from '../hooks/useSearchState';
import { clsx } from 'clsx';
export const InfiniteHits = ({ renderHit, renderEmpty, renderShowMore, showMoreButton = true, useInfiniteScroll = false, scrollThreshold = 0.1, fieldMapping, showMoreLabel = 'Show more', onHitClick, className, style, theme: customTheme, syncWithState = true, }) => {
    const { theme, stateManager } = useSearchContext();
    const { results, loading, currentPage, setPage } = useSearchState();
    const infiniteHitsTheme = customTheme || {};
    // Accumulated hits across pages
    const [accumulatedHits, setAccumulatedHits] = useState([]);
    const [isLoadingMore, setIsLoadingMore] = useState(false);
    const sentinelRef = useRef(null);
    const prevPageRef = useRef(currentPage);
    // Extract hits from results
    const extractHits = useCallback((response) => {
        if (!response)
            return [];
        if (response.results)
            return response.results;
        if (response.hits)
            return response.hits;
        if (Array.isArray(response))
            return response;
        return [];
    }, []);
    // Get current hits
    const currentHits = useMemo(() => extractHits(results), [results, extractHits]);
    // Calculate if we're on the last page
    const totalResults = results?.totalResults || results?.found || 0;
    const itemsPerPage = stateManager.getState().itemsPerPage || 10;
    const totalPages = Math.ceil(totalResults / itemsPerPage);
    const isLastPage = currentPage >= totalPages;
    // Accumulate hits when results change
    useEffect(() => {
        if (!currentHits.length)
            return;
        if (currentPage === 1) {
            // Reset accumulated hits on new search
            setAccumulatedHits(currentHits);
        }
        else if (currentPage > prevPageRef.current) {
            // Append new hits
            setAccumulatedHits(prev => [...prev, ...currentHits]);
        }
        prevPageRef.current = currentPage;
        setIsLoadingMore(false);
    }, [currentHits, currentPage]);
    // Reset when query changes
    useEffect(() => {
        if (currentPage === 1) {
            setAccumulatedHits(currentHits);
            prevPageRef.current = 1;
        }
    }, [results]);
    // Handle "Show More" click
    const handleShowMore = useCallback(() => {
        if (isLastPage || loading || isLoadingMore)
            return;
        setIsLoadingMore(true);
        if (syncWithState) {
            setPage(currentPage + 1);
        }
    }, [isLastPage, loading, isLoadingMore, syncWithState, setPage, currentPage]);
    // Infinite scroll with IntersectionObserver
    useEffect(() => {
        if (!useInfiniteScroll || !sentinelRef.current)
            return;
        const observer = new IntersectionObserver((entries) => {
            const entry = entries[0];
            if (entry.isIntersecting && !isLastPage && !loading && !isLoadingMore) {
                handleShowMore();
            }
        }, { threshold: scrollThreshold });
        observer.observe(sentinelRef.current);
        return () => observer.disconnect();
    }, [useInfiniteScroll, scrollThreshold, isLastPage, loading, isLoadingMore, handleShowMore]);
    // Extract field from hit
    const extractField = (hit, field) => {
        if (!fieldMapping || !fieldMapping[field]) {
            return hit[field] || '';
        }
        const mappedField = fieldMapping[field];
        return hit[mappedField] || '';
    };
    // Default hit renderer
    const defaultRenderHit = (hit, index) => {
        const title = extractField(hit, 'title') || hit.title || '';
        const description = extractField(hit, 'description') || hit.description || '';
        const image = extractField(hit, 'image') || hit.image || hit.imageUrl || '';
        const price = extractField(hit, 'price') || hit.price;
        return (React.createElement("div", { key: hit.id || index, className: infiniteHitsTheme.item, style: {
                display: 'flex',
                gap: theme.spacing.medium,
                padding: theme.spacing.medium,
                borderBottom: `1px solid ${theme.colors.border}`,
                cursor: onHitClick ? 'pointer' : 'default',
                transition: theme.transitions?.fast || '150ms ease-in-out',
            }, onClick: () => onHitClick?.(hit, index), role: onHitClick ? 'button' : undefined, tabIndex: onHitClick ? 0 : undefined },
            image && (React.createElement("img", { src: image, alt: title, style: {
                    width: '80px',
                    height: '80px',
                    objectFit: 'cover',
                    borderRadius: typeof theme.borderRadius === 'string'
                        ? theme.borderRadius
                        : theme.borderRadius.small,
                } })),
            React.createElement("div", { style: { flex: 1 } },
                React.createElement("h3", { style: {
                        margin: 0,
                        marginBottom: theme.spacing.small,
                        fontSize: theme.typography.fontSize.medium,
                        fontWeight: theme.typography.fontWeight?.semibold || 600,
                        color: theme.colors.text,
                    } }, title),
                description && (React.createElement("p", { style: {
                        margin: 0,
                        fontSize: theme.typography.fontSize.small,
                        color: theme.colors.textSecondary,
                        lineHeight: theme.typography.lineHeight?.normal || 1.5,
                    } }, description)),
                price && (React.createElement("span", { style: {
                        display: 'inline-block',
                        marginTop: theme.spacing.small,
                        fontSize: theme.typography.fontSize.medium,
                        fontWeight: theme.typography.fontWeight?.bold || 700,
                        color: theme.colors.primary,
                    } },
                    "$",
                    typeof price === 'number' ? price.toFixed(2) : price)))));
    };
    // Default empty state
    const defaultRenderEmpty = () => (React.createElement("div", { className: infiniteHitsTheme.empty, style: {
            padding: theme.spacing.large,
            textAlign: 'center',
            color: theme.colors.textSecondary,
        } }, "No results found"));
    // Default "Show More" button
    const defaultRenderShowMore = () => (React.createElement("button", { type: "button", onClick: handleShowMore, disabled: isLastPage || isLoadingMore, className: clsx(infiniteHitsTheme.loadMore, (isLastPage || isLoadingMore) && infiniteHitsTheme.loadMoreDisabled), style: {
            display: 'block',
            width: '100%',
            padding: theme.spacing.medium,
            marginTop: theme.spacing.medium,
            fontSize: theme.typography.fontSize.medium,
            fontWeight: theme.typography.fontWeight?.medium || 500,
            backgroundColor: isLastPage || isLoadingMore ? theme.colors.hover : theme.colors.primary,
            color: isLastPage || isLoadingMore ? theme.colors.textSecondary : '#ffffff',
            border: 'none',
            borderRadius: typeof theme.borderRadius === 'string'
                ? theme.borderRadius
                : theme.borderRadius.medium,
            cursor: isLastPage || isLoadingMore ? 'not-allowed' : 'pointer',
            transition: theme.transitions?.fast || '150ms ease-in-out',
        } }, isLastPage ? 'No more results' : showMoreLabel));
    if (loading && accumulatedHits.length === 0) {
        return React.createElement("div", { className: clsx(infiniteHitsTheme.root, className), style: style });
    }
    // Empty state
    if (!loading && accumulatedHits.length === 0) {
        return (React.createElement("div", { className: clsx(infiniteHitsTheme.root, className), style: style }, renderEmpty ? renderEmpty() : defaultRenderEmpty()));
    }
    return (React.createElement("div", { className: clsx(infiniteHitsTheme.root, className), style: style },
        React.createElement("div", { className: infiniteHitsTheme.list }, accumulatedHits.map((hit, index) => renderHit ? renderHit(hit, index) : defaultRenderHit(hit, index))),
        showMoreButton && !useInfiniteScroll && !isLastPage && (renderShowMore
            ? renderShowMore({ isLoading: isLoadingMore, isLastPage, onClick: handleShowMore })
            : defaultRenderShowMore()),
        useInfiniteScroll && !isLastPage && (React.createElement("div", { ref: sentinelRef, className: infiniteHitsTheme.sentinel, style: { height: '1px', visibility: 'hidden' }, "aria-hidden": "true" }))));
};
