/**
 * Facets Component
 *
 * Displays facet filters for search results with multiple display variants,
 * client-side search, count badges, and color swatch support.
 */
import React, { useState, useMemo, useRef, useEffect } from "react";
import { useSearchContext, useTrackContext } from "./SearchProvider";
import { useSearchState } from "../hooks/useSearchState";
import { useFilters } from "../hooks/useFilters";
import { useFilterImpressionTracker } from "../hooks/useFilterImpressionTracker";
import { log } from "@seekora-ai/ui-sdk-core";
import { clsx } from "clsx";
import { RangeSlider } from "./RangeSlider";
import { ensureSeekoraStyles } from "../styles/inject";
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/** Generate a deterministic colour from a string (used as fallback for color-swatch). */
function stringToColor(str) {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
        hash = str.charCodeAt(i) + ((hash << 5) - hash);
        hash |= 0; // Convert to 32-bit int
    }
    const h = Math.abs(hash) % 360;
    return `hsl(${h}, 65%, 55%)`;
}
// ---------------------------------------------------------------------------
// Chevron SVG icon for collapsible variant
// ---------------------------------------------------------------------------
const ChevronIcon = ({ expanded, color = "currentColor", size = 16 }) => (React.createElement("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: clsx("seekora-facet__chevron", expanded && "seekora-facet__chevron--expanded"), "aria-hidden": "true" },
    React.createElement("path", { d: "M4 6L8 10L12 6", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })));
// ---------------------------------------------------------------------------
// Checkmark SVG for selected color swatches
// ---------------------------------------------------------------------------
const CheckmarkIcon = ({ size = 16 }) => (React.createElement("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" },
    React.createElement("path", { d: "M3.5 8.5L6.5 11.5L12.5 4.5", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })));
// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------
export const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, renderFacet, renderFacetItem, maxItems = 10, showMore = true, className, style, theme: customTheme, variant = "checkbox", searchable = false, showCounts = true, colorMap, defaultCollapsed = false, size = "medium", facetRanges, useFiltersApi = false, disjunctiveFacets, hideEmptyFacets = true, defaultCollapsedFields, onFacetsAvailable, showMoreLabel = "Show more ({n} more)", showLessLabel = "Show less", }) => {
    const { theme, client, enableAnalytics } = useSearchContext();
    const { results: stateResults, refinements, addRefinement, removeRefinement, } = useSearchState();
    const facetsTheme = customTheme || {};
    // V4 "Filter Viewed" (event 12) — fires ONCE per facet group when its
    // container first crosses the viewport. filter_attribute = facet.field,
    // which is the SAME string SearchStateManager.emitFacetApplied stamps on
    // `Facet Applied` (filter_attribute: field), so the two events join cleanly
    // server-side. No-op when no trackContext is wired (mirrors
    // useImpressionTracker). SCRUM-259.
    const trackCtx = useTrackContext();
    const registerGroupRef = useFilterImpressionTracker({
        ctx: trackCtx,
        surface: "results_page",
    });
    // Inject canonical stylesheet once on mount
    useEffect(() => {
        ensureSeekoraStyles();
    }, []);
    // Use dedicated Filters API when useFiltersApi is enabled
    const { filters: filtersApiData, searchFacetValues } = useFilters(useFiltersApi ? { disjunctiveFacets } : { autoFetch: false });
    // expandedFacets is used for "Show more/less" in checkbox/color-swatch variants
    // AND for collapse/expand in collapsible variant.
    const [expandedFacets, setExpandedFacets] = useState({});
    const [searchTerms, setSearchTerms] = useState({});
    // activeItemIds: maps facet field -> the id of the currently keyboard-focused item
    const [activeItemIds, setActiveItemIds] = useState({});
    const listRefs = useRef({});
    // Use results from prop if provided, otherwise from state manager
    const results = resultsProp || stateResults;
    // -------------------------------------------------------------------
    // Extract facets from results (or Filters API)
    // -------------------------------------------------------------------
    const extractFacets = () => {
        if (facetsProp)
            return facetsProp;
        // When using Filters API, convert FilterField[] to Facet[]
        if (useFiltersApi && filtersApiData.length > 0) {
            log.verbose("Facets: Using Filters API data", {
                filterCount: filtersApiData.length,
            });
            return filtersApiData.map((filter) => ({
                field: filter.field || "",
                label: filter.field || "",
                items: (filter.values || []).map((v) => ({
                    value: v.value || "",
                    count: v.count || 0,
                    selected: refinements.some((r) => r.field === filter.field && r.value === v.value),
                })),
                stats: filter.stats?.min != null && filter.stats?.max != null
                    ? {
                        min: filter.stats.min,
                        max: filter.stats.max,
                        avg: filter.stats.avg,
                        sum: filter.stats.sum,
                    }
                    : undefined,
            }));
        }
        // Try to get facets from various locations in the response
        // Primary location: data.facets (widget_mode response structure)
        const rawFacets = results?.data?.facets ||
            results?.facets ||
            results?.data?.data?.facets ||
            null;
        log.verbose("Facets: Extracting facets", {
            hasResults: !!results,
            hasData: !!results?.data,
            rawFacets: rawFacets
                ? Array.isArray(rawFacets)
                    ? rawFacets.length
                    : "not array"
                : null,
            resultsKeys: results ? Object.keys(results) : [],
            dataKeys: results?.data ? Object.keys(results.data) : [],
            sampleFacet: rawFacets && Array.isArray(rawFacets) && rawFacets.length > 0
                ? rawFacets[0]
                : null,
        });
        // Ensure rawFacets is an array before mapping
        if (!rawFacets || !Array.isArray(rawFacets)) {
            log.verbose("Facets: No facets found in response", {
                rawFacetsType: rawFacets ? typeof rawFacets : "null",
                isArray: Array.isArray(rawFacets),
                resultsStructure: results
                    ? JSON.stringify(Object.keys(results))
                    : "null",
                dataStructure: results?.data
                    ? JSON.stringify(Object.keys(results.data))
                    : "null",
            });
            return [];
        }
        const extracted = rawFacets.map((facet) => {
            const fieldName = facet.field_name || facet.field;
            return {
                field: fieldName,
                label: facet.label || fieldName,
                items: Array.isArray(facet.counts)
                    ? facet.counts.map((count) => ({
                        value: count.value,
                        count: count.count,
                        selected: refinements.some((r) => r.field === fieldName && r.value === count.value),
                    }))
                    : [],
                stats: facet.stats || undefined,
            };
        });
        log.verbose("Facets: Extracted facets", {
            count: extracted.length,
            facets: extracted.map((f) => ({
                field: f.field,
                itemsCount: f.items.length,
            })),
        });
        return extracted;
    };
    const rawFacetList = extractFacets();
    const hasStats = (stats) => stats != null && (stats.min != null || stats.max != null);
    const facets = hideEmptyFacets
        ? rawFacetList.filter((f) => f.items.length > 0 || hasStats(f.stats))
        : rawFacetList;
    // Notify parent about facet availability — fires on every render path,
    // including first render with empty facets, so siblings can gate visibility.
    const facetCount = facets.length;
    useEffect(() => {
        onFacetsAvailable?.(facetCount > 0);
    }, [facetCount, onFacetsAvailable]);
    // -------------------------------------------------------------------
    // Handlers
    // -------------------------------------------------------------------
    const handleFacetToggle = (field, value, selected) => {
        const newSelected = !selected;
        log.verbose("Facets: Facet toggled", {
            field,
            value,
            selected: newSelected,
        });
        // Update state manager (automatically triggers search)
        if (newSelected) {
            addRefinement(field, value);
        }
        else {
            removeRefinement(field, value);
        }
        // Fire analytics event (B.2 — SCRUM-259)
        if (enableAnalytics && client.trackEvent) {
            Promise.resolve(client.trackEvent({
                event_name: "Filter Applied",
                metadata: {
                    filter_name: field,
                    filter_value: value,
                    selected: newSelected,
                },
            })).catch((err) => {
                const error = err instanceof Error ? err : new Error(String(err));
                log.error("Facets: Error tracking Filter Applied event", {
                    field,
                    value,
                    error: error.message,
                });
            });
        }
        // Call callback for backwards compatibility
        if (onFacetChange) {
            try {
                onFacetChange(field, value, newSelected);
            }
            catch (err) {
                const error = err instanceof Error ? err : new Error(String(err));
                log.error("Facets: Error in onFacetChange callback", {
                    field,
                    value,
                    selected: newSelected,
                    error: error.message,
                });
            }
        }
    };
    const toggleFacetExpansion = (field) => {
        setExpandedFacets((prev) => ({
            ...prev,
            [field]: !prev[field],
        }));
    };
    /** For collapsible variant — determine if a facet group is open. */
    const isFieldDefaultCollapsed = (field) => {
        if (defaultCollapsedFields?.includes(field))
            return true;
        return defaultCollapsed;
    };
    const isFacetGroupOpen = (field) => {
        if (field in expandedFacets) {
            return expandedFacets[field];
        }
        return !isFieldDefaultCollapsed(field);
    };
    const toggleCollapsible = (field) => {
        setExpandedFacets((prev) => ({
            ...prev,
            [field]: !(prev[field] ?? !isFieldDefaultCollapsed(field)),
        }));
    };
    const getSearchTerm = (field) => searchTerms[field] || "";
    const setSearchTerm = (field, term) => {
        setSearchTerms((prev) => ({ ...prev, [field]: term }));
    };
    /** Filter facet items by search term. */
    const filterItems = (items, field) => {
        if (!searchable)
            return items;
        const term = getSearchTerm(field).toLowerCase();
        if (!term)
            return items;
        return items.filter((item) => item.value.toLowerCase().includes(term));
    };
    // -------------------------------------------------------------------
    // Size helpers (data-size attr drives CSS vars; kept for swatch pixel size)
    // -------------------------------------------------------------------
    const swatchPxSize = useMemo(() => {
        switch (size) {
            case "small":
                return 24;
            case "large":
                return 40;
            case "medium":
            default:
                return 32;
        }
    }, [size]);
    // -------------------------------------------------------------------
    // Count badge renderer
    // -------------------------------------------------------------------
    const renderCountBadge = (count) => {
        if (!showCounts)
            return null;
        return (React.createElement("span", { className: clsx("seekora-facet__count", facetsTheme.countBadge) }, count));
    };
    // -------------------------------------------------------------------
    // Search input renderer
    // -------------------------------------------------------------------
    const renderSearchInput = (facet) => {
        if (!searchable)
            return null;
        return (React.createElement("input", { type: "text", value: getSearchTerm(facet.field), onChange: (e) => setSearchTerm(facet.field, e.target.value), placeholder: `Search ${facet.label || facet.field}...`, className: clsx("seekora-facet__search-input", facetsTheme.searchInput), "aria-label": `Search within ${facet.label || facet.field}` }));
    };
    // -------------------------------------------------------------------
    // Checkbox variant item renderer (original behaviour, preserved)
    // -------------------------------------------------------------------
    const defaultRenderFacetItem = (item, facet, index) => {
        const isExpanded = expandedFacets[facet.field] || index < maxItems;
        if (!isExpanded && index >= maxItems) {
            return null;
        }
        const isChecked = refinements.some((r) => r.field === facet.field && r.value === item.value) ||
            item.selected ||
            false;
        const itemId = getFacetItemId(facet.field, item.value);
        const isActive = activeItemIds[facet.field] === itemId;
        return (React.createElement("div", { key: `${facet.field}-${item.value}`, id: itemId, className: clsx("seekora-facet__item", facetsTheme.facetItem, isChecked && facetsTheme.facetItemActive), tabIndex: -1, "data-facet-field": facet.field, "data-facet-value": item.value, "data-active": isActive || undefined, onClick: () => handleFacetToggle(facet.field, item.value, item.selected || false) },
            React.createElement("input", { type: "checkbox", checked: refinements.some((r) => r.field === facet.field && r.value === item.value) ||
                    item.selected ||
                    false, onChange: () => handleFacetToggle(facet.field, item.value, item.selected || false), className: clsx("seekora-facet__checkbox", facetsTheme.checkbox), "aria-label": `Filter by ${item.value}` }),
            React.createElement("span", { className: clsx("seekora-facet__label", facetsTheme.facetItemLabel) }, item.value),
            renderCountBadge(item.count)));
    };
    // -------------------------------------------------------------------
    // Color swatch variant item renderer
    // -------------------------------------------------------------------
    const renderColorSwatchItem = (item, facet, index) => {
        const isExpanded = expandedFacets[facet.field] || index < maxItems;
        if (!isExpanded && index >= maxItems) {
            return null;
        }
        const isChecked = refinements.some((r) => r.field === facet.field && r.value === item.value) ||
            item.selected ||
            false;
        const color = colorMap?.[item.value] ?? stringToColor(item.value);
        const itemId = getFacetItemId(facet.field, item.value);
        const isActive = activeItemIds[facet.field] === itemId;
        return (React.createElement("div", { key: `${facet.field}-${item.value}`, id: itemId, className: clsx("seekora-facet__item", "seekora-facet__item--swatch", facetsTheme.facetItem, isChecked && facetsTheme.facetItemActive), role: "option", "aria-selected": isChecked, "aria-checked": isChecked, tabIndex: -1, "data-facet-field": facet.field, "data-facet-value": item.value, "data-active": isActive || undefined, onClick: () => handleFacetToggle(facet.field, item.value, item.selected || false), title: `${item.value}${showCounts ? ` (${item.count})` : ""}` },
            React.createElement("span", { className: clsx("seekora-facet__swatch", isChecked && "seekora-facet__swatch--selected", facetsTheme.colorSwatch, isChecked && facetsTheme.colorSwatchSelected), style: { "--seekora-facet-swatch-color": color } }, isChecked && (React.createElement("span", { className: clsx("seekora-facet__swatch-inner", facetsTheme.colorSwatchInner) },
                React.createElement(CheckmarkIcon, { size: Math.round(swatchPxSize * 0.5) })))),
            React.createElement("span", { className: clsx("seekora-facet__label", facetsTheme.facetItemLabel) }, item.value),
            showCounts && (React.createElement("span", { className: clsx("seekora-facet__swatch-count", facetsTheme.countBadge) }, item.count))));
    };
    // -------------------------------------------------------------------
    // Item renderer dispatcher
    // -------------------------------------------------------------------
    const renderItem = (item, facet, index) => {
        if (renderFacetItem) {
            return renderFacetItem(item, facet, index);
        }
        switch (variant) {
            case "color-swatch":
                return renderColorSwatchItem(item, facet, index);
            case "collapsible":
            case "checkbox":
            default:
                return defaultRenderFacetItem(item, facet, index);
        }
    };
    // -------------------------------------------------------------------
    // Keyboard handler (shared across variants)
    // -------------------------------------------------------------------
    const getFacetItemId = (field, value) => `seekora-facet-${field}-${value}`.replace(/[^a-zA-Z0-9-_]/g, "-");
    const handleListKeyDown = (e, visibleItems, facet) => {
        const currentActiveId = activeItemIds[facet.field];
        const currentIdx = currentActiveId
            ? visibleItems.findIndex((item) => getFacetItemId(facet.field, item.value) === currentActiveId)
            : -1;
        const moveTo = (nextIdx) => {
            const nextItem = visibleItems[nextIdx];
            if (!nextItem)
                return;
            const nextId = getFacetItemId(facet.field, nextItem.value);
            setActiveItemIds((prev) => ({ ...prev, [facet.field]: nextId }));
            // Scroll new item into view
            const listEl = listRefs.current[facet.field];
            if (listEl) {
                const el = listEl.querySelector(`#${CSS.escape(nextId)}`);
                el?.scrollIntoView({ block: "nearest" });
            }
        };
        if (e.key === "ArrowDown") {
            e.preventDefault();
            moveTo(Math.min(currentIdx + 1, visibleItems.length - 1));
        }
        else if (e.key === "ArrowUp") {
            e.preventDefault();
            moveTo(Math.max(currentIdx - 1, 0));
        }
        else if (e.key === "Enter" || e.key === " ") {
            e.preventDefault();
            if (currentIdx >= 0 && currentIdx < visibleItems.length) {
                handleFacetToggle(facet.field, visibleItems[currentIdx].value, visibleItems[currentIdx].selected || false);
            }
        }
    };
    // -------------------------------------------------------------------
    // Show more / less buttons (shared)
    // -------------------------------------------------------------------
    const renderShowMoreLess = (facet, filteredItems) => {
        const isExpanded = expandedFacets[facet.field] || false;
        const hasMore = filteredItems.length > maxItems;
        return (React.createElement(React.Fragment, null,
            showMore && hasMore && !isExpanded && (React.createElement("button", { type: "button", className: "seekora-facet__show-more", onClick: () => toggleFacetExpansion(facet.field) }, showMoreLabel.replace("{n}", String(filteredItems.length - maxItems)))),
            isExpanded && hasMore && (React.createElement("button", { type: "button", className: "seekora-facet__show-more", onClick: () => toggleFacetExpansion(facet.field) }, showLessLabel))));
    };
    // -------------------------------------------------------------------
    // Default facet group renderer — Checkbox variant
    // -------------------------------------------------------------------
    const renderCheckboxFacet = (facet, _index) => {
        const filteredItems = filterItems(facet.items, facet.field);
        const isExpanded = expandedFacets[facet.field] || false;
        const visibleItems = isExpanded
            ? filteredItems
            : filteredItems.slice(0, maxItems);
        return (React.createElement("div", { key: facet.field, ref: registerGroupRef(facet.field), className: clsx("seekora-facet", facetsTheme.facet), "data-variant": "checkbox", "data-size": size },
            React.createElement("h3", { className: clsx("seekora-facet__title", facetsTheme.facetTitle) }, facet.label || facet.field),
            renderSearchInput(facet),
            React.createElement("div", { className: clsx("seekora-facet__list", facetsTheme.facetList), role: "listbox", "aria-label": `${facet.label || facet.field} filters`, "aria-activedescendant": activeItemIds[facet.field] || undefined, tabIndex: 0, ref: (el) => {
                    listRefs.current[facet.field] = el;
                }, onKeyDown: (e) => handleListKeyDown(e, visibleItems, facet) }, visibleItems.map((item, itemIndex) => renderItem(item, facet, itemIndex))),
            renderShowMoreLess(facet, filteredItems)));
    };
    // -------------------------------------------------------------------
    // Color-swatch facet group renderer
    // -------------------------------------------------------------------
    const renderColorSwatchFacet = (facet, _index) => {
        const filteredItems = filterItems(facet.items, facet.field);
        const isExpanded = expandedFacets[facet.field] || false;
        const visibleItems = isExpanded
            ? filteredItems
            : filteredItems.slice(0, maxItems);
        return (React.createElement("div", { key: facet.field, ref: registerGroupRef(facet.field), className: clsx("seekora-facet", facetsTheme.facet), "data-variant": "color-swatch", "data-size": size },
            React.createElement("h3", { className: clsx("seekora-facet__title", facetsTheme.facetTitle) }, facet.label || facet.field),
            renderSearchInput(facet),
            React.createElement("div", { className: clsx("seekora-facet__list", facetsTheme.facetList), role: "listbox", "aria-label": `${facet.label || facet.field} filters`, "aria-activedescendant": activeItemIds[facet.field] || undefined, tabIndex: 0, ref: (el) => {
                    listRefs.current[facet.field] = el;
                }, onKeyDown: (e) => handleListKeyDown(e, visibleItems, facet) }, visibleItems.map((item, itemIndex) => renderItem(item, facet, itemIndex))),
            renderShowMoreLess(facet, filteredItems)));
    };
    // -------------------------------------------------------------------
    // Collapsible facet group renderer
    // -------------------------------------------------------------------
    const renderCollapsibleFacet = (facet, _index) => {
        const isOpen = isFacetGroupOpen(facet.field);
        const filteredItems = filterItems(facet.items, facet.field);
        const isShowMoreExpanded = expandedFacets[`_items_${facet.field}`] || false;
        const visibleItems = isShowMoreExpanded
            ? filteredItems
            : filteredItems.slice(0, maxItems);
        const hasMore = filteredItems.length > maxItems;
        return (React.createElement("div", { key: facet.field, ref: registerGroupRef(facet.field), className: clsx("seekora-facet", facetsTheme.facet), "data-variant": "collapsible", "data-state": isOpen ? "expanded" : "collapsed", "data-size": size },
            React.createElement("button", { type: "button", className: clsx("seekora-facet__collapsible-header", facetsTheme.collapsibleHeader), onClick: () => toggleCollapsible(facet.field), "aria-expanded": isOpen, "aria-controls": `facet-group-${facet.field}` },
                React.createElement("span", { className: clsx("seekora-facet__title", facetsTheme.facetTitle) }, facet.label || facet.field),
                React.createElement("span", { className: clsx("seekora-facet__collapsible-icon", facetsTheme.collapsibleIcon) },
                    React.createElement(ChevronIcon, { expanded: isOpen, color: "currentColor" }))),
            isOpen && (React.createElement("div", { id: `facet-group-${facet.field}`, className: "seekora-facet__collapsible-body" },
                renderSearchInput(facet),
                React.createElement("div", { className: clsx("seekora-facet__list", facetsTheme.facetList), role: "listbox", "aria-label": `${facet.label || facet.field} filters`, "aria-activedescendant": activeItemIds[facet.field] || undefined, tabIndex: 0, ref: (el) => {
                        listRefs.current[facet.field] = el;
                    }, onKeyDown: (e) => handleListKeyDown(e, visibleItems, facet) }, visibleItems.map((item, itemIndex) => renderItem(item, facet, itemIndex))),
                showMore && hasMore && !isShowMoreExpanded && (React.createElement("button", { type: "button", className: "seekora-facet__show-more", onClick: () => setExpandedFacets((prev) => ({
                        ...prev,
                        [`_items_${facet.field}`]: true,
                    })) }, showMoreLabel.replace("{n}", String(filteredItems.length - maxItems)))),
                isShowMoreExpanded && hasMore && (React.createElement("button", { type: "button", className: "seekora-facet__show-more", onClick: () => setExpandedFacets((prev) => ({
                        ...prev,
                        [`_items_${facet.field}`]: false,
                    })) }, showLessLabel))))));
    };
    // -------------------------------------------------------------------
    // Render-type detection for numeric / range facets
    // -------------------------------------------------------------------
    const determineFacetRenderType = (fieldName, stats) => {
        // If explicit range config exists for this field → range buttons
        if (facetRanges?.some((rc) => rc.field === fieldName)) {
            return "range-buttons";
        }
        // If stats with valid min/max → range slider
        if (stats &&
            typeof stats.min === "number" &&
            typeof stats.max === "number" &&
            stats.min !== stats.max) {
            return "range-slider";
        }
        return "list";
    };
    // -------------------------------------------------------------------
    // Range button facet renderer
    // -------------------------------------------------------------------
    const renderRangeButtonFacet = (facet, _index) => {
        const rangeConfig = facetRanges?.find((rc) => rc.field === facet.field);
        if (!rangeConfig)
            return null;
        // Build a lookup from item value → count
        const countMap = new Map();
        facet.items.forEach((item) => countMap.set(item.value, item.count));
        // Detect currently active range from refinements
        const activeMin = refinements.find((r) => r.field === facet.field && r.value.startsWith(">="));
        const activeMax = refinements.find((r) => r.field === facet.field && r.value.startsWith("<="));
        const activeFromVal = activeMin
            ? parseFloat(activeMin.value.slice(2))
            : undefined;
        const activeToVal = activeMax
            ? parseFloat(activeMax.value.slice(2))
            : undefined;
        const isRangeActive = (range) => {
            const fromMatch = range.from === undefined
                ? activeFromVal === undefined
                : activeFromVal === range.from;
            const toMatch = range.to === undefined
                ? activeToVal === undefined
                : activeToVal === range.to;
            return fromMatch && toMatch;
        };
        const handleRangeClick = (range) => {
            // Clear existing range refinements for this field
            refinements
                .filter((r) => r.field === facet.field)
                .forEach((r) => removeRefinement(facet.field, r.value, false));
            if (isRangeActive(range)) {
                // Was active → just clear (already removed above), trigger search
                addRefinement(facet.field, "__noop__", false);
                removeRefinement(facet.field, "__noop__", true);
                return;
            }
            // Set new range
            if (range.from !== undefined) {
                addRefinement(facet.field, `>=${range.from}`, false);
            }
            if (range.to !== undefined) {
                addRefinement(facet.field, `<=${range.to}`, true);
            }
            else if (range.from !== undefined) {
                // Only "from" set — trigger search
                addRefinement(facet.field, `>=${range.from}`, true);
            }
        };
        const hasActiveRange = activeMin !== undefined || activeMax !== undefined;
        const handleClear = () => {
            refinements
                .filter((r) => r.field === facet.field)
                .forEach((r) => removeRefinement(facet.field, r.value, false));
            // Trigger search after clearing
            addRefinement(facet.field, "__noop__", false);
            removeRefinement(facet.field, "__noop__", true);
        };
        return (React.createElement("div", { key: facet.field, ref: registerGroupRef(facet.field), className: clsx("seekora-facet", facetsTheme.facet), "data-variant": "range-buttons", "data-size": size },
            React.createElement("h3", { className: clsx("seekora-facet__title", facetsTheme.facetTitle) }, facet.label || facet.field),
            React.createElement("div", { className: "seekora-facet__range-buttons" }, rangeConfig.ranges.map((range) => {
                const count = countMap.get(range.label) ?? 0;
                const active = isRangeActive(range);
                return (React.createElement("button", { key: range.label, type: "button", className: clsx("seekora-facet__range-btn", active && "seekora-facet__range-btn--active", facetsTheme.rangeButton, active && facetsTheme.rangeButtonActive), disabled: count === 0 && !active, onClick: () => handleRangeClick(range) },
                    range.label,
                    showCounts && (React.createElement("span", { className: clsx("seekora-facet__range-btn-count", facetsTheme.rangeButtonCount) },
                        "(",
                        count,
                        ")"))));
            })),
            hasActiveRange && (React.createElement("button", { type: "button", className: clsx("seekora-facet__range-clear", facetsTheme.rangeClear), onClick: handleClear }, "Clear"))));
    };
    // -------------------------------------------------------------------
    // Range slider facet renderer
    // -------------------------------------------------------------------
    const renderRangeSliderFacet = (facet, _index) => {
        if (!facet.stats)
            return null;
        const { min: statsMin, max: statsMax } = facet.stats;
        // Auto-detect formatting for common field names
        const fieldLower = facet.field.toLowerCase();
        const isPriceField = fieldLower.includes("price") ||
            fieldLower.includes("cost") ||
            fieldLower.includes("amount");
        const formatValue = isPriceField
            ? (v) => `$${v.toFixed(2)}`
            : (v) => v.toString();
        // Determine step: use 0.01 for price, 1 for integer ranges, 0.1 otherwise
        const range = statsMax - statsMin;
        const step = isPriceField ? 0.01 : range > 10 ? 1 : 0.1;
        // Check if there's an active range refinement
        const hasActiveRange = refinements.some((r) => r.field === facet.field &&
            (r.value.startsWith(">=") || r.value.startsWith("<=")));
        const handleClear = () => {
            refinements
                .filter((r) => r.field === facet.field &&
                (r.value.startsWith(">=") || r.value.startsWith("<=")))
                .forEach((r) => removeRefinement(facet.field, r.value, false));
            // Trigger search after clearing
            addRefinement(facet.field, "__noop__", false);
            removeRefinement(facet.field, "__noop__", true);
        };
        return (React.createElement("div", { key: facet.field, ref: registerGroupRef(facet.field), className: clsx("seekora-facet", facetsTheme.facet), "data-variant": "range-slider", "data-size": size },
            React.createElement("div", { className: "seekora-facet__range-header" },
                React.createElement("h3", { className: clsx("seekora-facet__title", facetsTheme.facetTitle) }, facet.label || facet.field),
                hasActiveRange && (React.createElement("button", { type: "button", className: clsx("seekora-facet__range-clear", facetsTheme.rangeClear), onClick: handleClear }, "Clear"))),
            React.createElement(RangeSlider, { field: facet.field, min: statsMin, max: statsMax, step: step, formatValue: formatValue, syncWithState: true })));
    };
    // -------------------------------------------------------------------
    // Default facet renderer dispatcher
    // -------------------------------------------------------------------
    const defaultRenderFacet = (facet, index) => {
        const renderType = determineFacetRenderType(facet.field, facet.stats);
        if (renderType === "range-buttons") {
            return renderRangeButtonFacet(facet, index);
        }
        if (renderType === "range-slider") {
            return renderRangeSliderFacet(facet, index);
        }
        switch (variant) {
            case "color-swatch":
                return renderColorSwatchFacet(facet, index);
            case "collapsible":
                return renderCollapsibleFacet(facet, index);
            case "checkbox":
            default:
                return renderCheckboxFacet(facet, index);
        }
    };
    // -------------------------------------------------------------------
    // Empty state
    // -------------------------------------------------------------------
    if (facets.length === 0) {
        log.verbose("Facets: No facets to display", {
            hasResults: !!results,
            resultsType: results ? typeof results : "null",
        });
        // Return a placeholder instead of null for debugging
        if (process.env.NODE_ENV === "development") {
            return React.createElement("div", { className: "seekora-facets__empty" }, "No facets available");
        }
        return null;
    }
    // -------------------------------------------------------------------
    // Render
    // -------------------------------------------------------------------
    return (React.createElement("div", { className: clsx("seekora-facets", facetsTheme.container, className), "data-variant": variant, "data-size": size, style: style }, facets.map((facet, index) => {
        return renderFacet
            ? renderFacet(facet, index)
            : defaultRenderFacet(facet, index);
    })));
};
