/**
 * SortBy Component
 *
 * Displays sort options for search results in multiple display variants:
 * - dropdown (default) — native select element
 * - button-group — horizontal row of toggle buttons
 * - radio-group — vertical list of radio inputs
 *
 * Integrates with SearchStateManager for automatic state sync.
 *
 * CSS Variables (apply on a parent element to customize):
 * --seekora-sort-bg           — background color
 * --seekora-sort-color        — text color
 * --seekora-sort-border       — border color
 * --seekora-sort-active-bg    — active item background
 * --seekora-sort-active-color — active item text color
 */
import React, { useCallback, useEffect, useId } from "react";
import { useSearchContext } from "./SearchProvider";
import { useSearchState } from "../hooks/useSearchState";
import { clsx } from "clsx";
import { CustomSelect } from "./primitives/CustomSelect";
import { ensureSeekoraStyles } from "../styles/inject";
// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------
export const SortBy = ({ options, value: valueProp, defaultValue, onSortChange, renderSelect, className, style, theme: customTheme, placeholder = "Sort by...", syncWithState = true, variant = "dropdown", label, showLabel, size = "medium", disableWhenEmpty = true, }) => {
    const { theme, client, enableAnalytics } = useSearchContext();
    const { sortBy: stateManagerSortBy, setSortBy, results } = useSearchState();
    const sortByTheme = customTheme || {};
    const instanceId = useId();
    useEffect(() => {
        ensureSeekoraStyles();
    }, []);
    // Resolve "auto" options from search response's sort_options
    const resolvedOptions = React.useMemo(() => {
        if (options !== "auto")
            return options;
        const res = results;
        const sortOpts = res?.data?.sort_options ?? res?.sort_options ?? [];
        if (!Array.isArray(sortOpts) || sortOpts.length === 0) {
            return [{ value: "relevance", label: "Relevance" }];
        }
        return [
            { value: "relevance", label: "Relevance" },
            ...sortOpts.filter((o) => o.label &&
                !o.label.includes(": Ascending") &&
                !o.label.includes(": Descending")),
        ];
    }, [options, results]);
    // Compute total results for disableWhenEmpty
    const res = results;
    const totalResults = res?.totalResults || res?.data?.total_results || 0;
    const isDisabled = disableWhenEmpty && totalResults === 0;
    // Determine whether the label should render.
    const shouldShowLabel = showLabel !== undefined ? showLabel : !!label;
    // ------ State ----------------------------------------------------------
    const [internalValue, setInternalValue] = React.useState(defaultValue || resolvedOptions[0]?.value || "");
    // Sync with StateManager on mount if defaultValue is set
    useEffect(() => {
        if (syncWithState && defaultValue && !stateManagerSortBy) {
            setSortBy(defaultValue, false); // Don't trigger search on initial sync
        }
    }, []); // eslint-disable-line react-hooks/exhaustive-deps
    // Determine the current value: controlled prop > StateManager > internal
    const value = valueProp !== undefined
        ? valueProp
        : syncWithState && stateManagerSortBy
            ? stateManagerSortBy
            : internalValue;
    // ------ Handlers -------------------------------------------------------
    const handleChange = (e) => {
        applyValue(e.target.value);
    };
    const applyValue = useCallback((newValue) => {
        setInternalValue(newValue);
        if (syncWithState) {
            setSortBy(newValue);
        }
        // Fire analytics event (B.2 — SCRUM-259)
        if (enableAnalytics && client.trackEvent) {
            const selectedOption = resolvedOptions.find((o) => o.value === newValue);
            Promise.resolve(client.trackEvent({
                event_name: "Sort Applied",
                metadata: {
                    sort_field: newValue,
                    sort_label: selectedOption?.label ?? newValue,
                },
            })).catch((err) => {
                const error = err instanceof Error ? err : new Error(String(err));
                // eslint-disable-next-line no-console
                console.error("SortBy: Error tracking Sort Applied event", error.message);
            });
        }
        if (onSortChange) {
            onSortChange(newValue);
        }
    }, [
        syncWithState,
        setSortBy,
        onSortChange,
        enableAnalytics,
        client,
        resolvedOptions,
    ]);
    // ------ CSS variable bridge (theme tokens → CSS vars) ------------------
    const cssVarStyle = {
        "--seekora-sort-bg": theme.colors.background,
        "--seekora-sort-color": theme.colors.text,
        "--seekora-sort-border": theme.colors.border,
        "--seekora-sort-active-bg": theme.colors.primary,
        "--seekora-sort-active-color": theme.colors.background,
    };
    // ------ Label ----------------------------------------------------------
    const labelElement = shouldShowLabel && label ? (React.createElement("span", { className: clsx("seekora-sort__label", sortByTheme.label), "data-size": size }, label)) : null;
    // ------ Dropdown variant (original) ------------------------------------
    if (variant === "dropdown") {
        if (renderSelect) {
            return (React.createElement("div", { className: clsx("seekora-sort", sortByTheme.container, className), "data-variant": "dropdown", "data-size": size, "data-disabled": isDisabled ? "true" : undefined, style: { ...cssVarStyle, ...style } },
                labelElement,
                renderSelect({
                    value,
                    onChange: handleChange,
                    options: resolvedOptions,
                })));
        }
        return (React.createElement("div", { className: clsx("seekora-sort", sortByTheme.container, className), "data-variant": "dropdown", "data-size": size, "data-disabled": isDisabled ? "true" : undefined, style: { ...cssVarStyle, ...style } },
            labelElement,
            React.createElement(CustomSelect, { value: value, onChange: applyValue, options: resolvedOptions, placeholder: placeholder, "aria-label": label || "Sort results", className: clsx("seekora-sort__select", sortByTheme.select), disabled: isDisabled })));
    }
    // ------ Button group variant -------------------------------------------
    if (variant === "button-group") {
        return (React.createElement("div", { className: clsx("seekora-sort", sortByTheme.container, className), "data-variant": "button-group", "data-size": size, "data-disabled": isDisabled ? "true" : undefined, style: { ...cssVarStyle, ...style } },
            labelElement,
            React.createElement("div", { role: "group", "aria-label": label || "Sort results", className: clsx("seekora-sort__button-group", sortByTheme.buttonGroup) }, resolvedOptions.map((option, index) => {
                const isActive = option.value === value;
                return (React.createElement("button", { key: option.value, type: "button", role: "button", "aria-pressed": isActive, "data-active": isActive || undefined, "data-last": index === resolvedOptions.length - 1 || undefined, onClick: () => applyValue(option.value), disabled: isDisabled, className: clsx("seekora-sort__button-group-item", isActive && "seekora-sort__button-group-item--active", sortByTheme.buttonGroupItem, isActive && sortByTheme.buttonGroupItemActive) }, option.label));
            }))));
    }
    // ------ Radio group variant --------------------------------------------
    if (variant === "radio-group") {
        const radioName = `seekora-sort-${instanceId}`;
        return (React.createElement("div", { className: clsx("seekora-sort", sortByTheme.container, className), "data-variant": "radio-group", "data-size": size, "data-disabled": isDisabled ? "true" : undefined, style: { ...cssVarStyle, ...style } },
            labelElement,
            React.createElement("div", { role: "radiogroup", "aria-label": label || "Sort results", className: clsx("seekora-sort__radio-group", sortByTheme.radioGroup) }, resolvedOptions.map((option) => {
                const isActive = option.value === value;
                const radioId = `${radioName}-${option.value}`;
                return (React.createElement("label", { key: option.value, htmlFor: radioId, "data-active": isActive || undefined, className: clsx("seekora-sort__radio-item", isActive && "seekora-sort__radio-item--active", sortByTheme.radioItem, isActive && sortByTheme.radioItemActive) },
                    React.createElement("input", { type: "radio", id: radioId, name: radioName, value: option.value, checked: isActive, onChange: () => applyValue(option.value), disabled: isDisabled, className: "seekora-sort__radio-input" }),
                    React.createElement("span", { className: clsx("seekora-sort__radio-label", sortByTheme.radioLabel) }, option.label)));
            }))));
    }
    // Fallback — should never reach here, but satisfies TS exhaustiveness
    return null;
};
