/**
 * 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";
import { ensureSeekoraStyles } from "../styles/inject";
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 || {};
    useEffect(() => {
        ensureSeekoraStyles();
    }, []);
    // 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: clsx("seekora-infinite-hits__item", infiniteHitsTheme.item, onHitClick && "seekora-infinite-hits__item--clickable"), onClick: () => onHitClick?.(hit, index), role: onHitClick ? "button" : undefined, tabIndex: onHitClick ? 0 : undefined },
            image && (React.createElement("img", { src: image, alt: title, className: "seekora-infinite-hits__item-image" })),
            React.createElement("div", { className: "seekora-infinite-hits__item-body" },
                React.createElement("h3", { className: "seekora-infinite-hits__item-title" }, title),
                description && (React.createElement("p", { className: "seekora-infinite-hits__item-description" }, description)),
                price && (React.createElement("span", { className: "seekora-infinite-hits__item-price" },
                    "$",
                    typeof price === "number" ? price.toFixed(2) : price)))));
    };
    // Default empty state
    const defaultRenderEmpty = () => (React.createElement("div", { className: clsx("seekora-infinite-hits__empty", infiniteHitsTheme.empty) }, "No results found"));
    // Default "Show More" button
    const defaultRenderShowMore = () => (React.createElement("button", { type: "button", onClick: handleShowMore, disabled: isLastPage || isLoadingMore, className: clsx("seekora-infinite-hits__load-more", (isLastPage || isLoadingMore) &&
            "seekora-infinite-hits__load-more--disabled", infiniteHitsTheme.loadMore, (isLastPage || isLoadingMore) && infiniteHitsTheme.loadMoreDisabled) }, isLastPage ? "No more results" : showMoreLabel));
    if (loading && accumulatedHits.length === 0) {
        return (React.createElement("div", { className: clsx("seekora-infinite-hits", "seekora-infinite-hits--loading", infiniteHitsTheme.root, className), style: style }));
    }
    // Empty state
    if (!loading && accumulatedHits.length === 0) {
        return (React.createElement("div", { className: clsx("seekora-infinite-hits", infiniteHitsTheme.root, className), style: style }, renderEmpty ? renderEmpty() : defaultRenderEmpty()));
    }
    return (React.createElement("div", { className: clsx("seekora-infinite-hits", infiniteHitsTheme.root, className), style: style },
        React.createElement("div", { className: clsx("seekora-infinite-hits__list", 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: clsx("seekora-infinite-hits__sentinel", infiniteHitsTheme.sentinel), "aria-hidden": "true" }))));
};
