/**
 * RangeSlider Component
 *
 * Visual slider for numeric range filtering
 * Alternative to RangeInput for a more interactive UX
 */
import React, { useState, useCallback, useEffect, useRef } from "react";
import { useSearchContext } from "./SearchProvider";
import { useSearchState } from "../hooks/useSearchState";
import { ensureSeekoraStyles } from "../styles/inject";
import { clsx } from "clsx";
export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: currentMinProp, currentMax: currentMaxProp, onRangeChange, formatValue = (v) => v.toString(), className, style, theme: customTheme, showValues = true, syncWithState = true, debounceMs = 300, }) => {
    useEffect(() => {
        ensureSeekoraStyles();
    }, []);
    const { theme } = useSearchContext();
    const { refinements, addRefinement, removeRefinement } = useSearchState();
    const rangeSliderTheme = customTheme || {};
    // Parse current range from StateManager
    // NOTE: computed every render (no useMemo) because the state manager mutates
    // the refinements array in place — the reference never changes.
    let stateRange;
    if (!syncWithState) {
        stateRange = { min: undefined, max: undefined };
    }
    else {
        let minVal;
        let maxVal;
        refinements.forEach((r) => {
            if (r.field === field) {
                const minMatch = r.value.match(/^>=(\d+(?:\.\d+)?)$/);
                if (minMatch)
                    minVal = parseFloat(minMatch[1]);
                const maxMatch = r.value.match(/^<=(\d+(?:\.\d+)?)$/);
                if (maxMatch)
                    maxVal = parseFloat(maxMatch[1]);
            }
        });
        stateRange = { min: minVal, max: maxVal };
    }
    const [internalMin, setInternalMin] = useState(currentMinProp ?? stateRange.min ?? min);
    const [internalMax, setInternalMax] = useState(currentMaxProp ?? stateRange.max ?? max);
    const isDraggingRef = useRef(false);
    const debounceRef = useRef(null);
    const pendingMinRef = useRef(internalMin);
    const pendingMaxRef = useRef(internalMax);
    // Sync with StateManager changes (only when stateRange actually changes, not on drag)
    useEffect(() => {
        if (syncWithState && !isDraggingRef.current) {
            if (stateRange.min !== undefined)
                setInternalMin(stateRange.min);
            else
                setInternalMin(min);
            if (stateRange.max !== undefined)
                setInternalMax(stateRange.max);
            else
                setInternalMax(max);
        }
    }, [syncWithState, stateRange.min, stateRange.max, min, max]);
    // Update StateManager with range refinements
    const updateStateManager = useCallback((minVal, maxVal) => {
        if (!syncWithState)
            return;
        // Remove existing range refinements for this field
        refinements.forEach((r) => {
            if (r.field === field) {
                removeRefinement(field, r.value, false);
            }
        });
        // Add new range refinements — trigger search on the last one added
        const setMin = minVal > min;
        const setMax = maxVal < max;
        if (setMin && setMax) {
            addRefinement(field, `>=${minVal}`, false);
            addRefinement(field, `<=${maxVal}`, true);
        }
        else if (setMin) {
            addRefinement(field, `>=${minVal}`, true);
        }
        else if (setMax) {
            addRefinement(field, `<=${maxVal}`, true);
        }
    }, [
        syncWithState,
        field,
        refinements,
        addRefinement,
        removeRefinement,
        min,
        max,
    ]);
    // Debounced update (during drag only)
    const debouncedUpdate = useCallback((minVal, maxVal) => {
        pendingMinRef.current = minVal;
        pendingMaxRef.current = maxVal;
        if (debounceRef.current) {
            clearTimeout(debounceRef.current);
        }
        debounceRef.current = setTimeout(() => {
            updateStateManager(minVal, maxVal);
            if (onRangeChange) {
                onRangeChange(minVal, maxVal);
            }
        }, debounceMs);
    }, [updateStateManager, onRangeChange, debounceMs]);
    // Handle min slider change
    const handleMinChange = (e) => {
        const value = Math.min(Number(e.target.value), internalMax - step);
        setInternalMin(value);
        isDraggingRef.current = true;
        debouncedUpdate(value, internalMax);
    };
    // Handle max slider change
    const handleMaxChange = (e) => {
        const value = Math.max(Number(e.target.value), internalMin + step);
        setInternalMax(value);
        isDraggingRef.current = true;
        debouncedUpdate(internalMin, value);
    };
    // Handle drag end — flush pending update immediately
    const handleDragEnd = () => {
        isDraggingRef.current = false;
        // Cancel the debounce and commit immediately
        if (debounceRef.current) {
            clearTimeout(debounceRef.current);
            debounceRef.current = null;
        }
        updateStateManager(pendingMinRef.current, pendingMaxRef.current);
        if (onRangeChange) {
            onRangeChange(pendingMinRef.current, pendingMaxRef.current);
        }
    };
    // Handle keyboard navigation for enhanced control (Shift+Arrow for 10x step, Home/End)
    const handleMinKeyDown = (e) => {
        let newValue = null;
        if (e.key === "Home") {
            e.preventDefault();
            newValue = min;
        }
        else if (e.key === "End") {
            e.preventDefault();
            newValue = internalMax - step;
        }
        else if (e.shiftKey && (e.key === "ArrowLeft" || e.key === "ArrowDown")) {
            e.preventDefault();
            newValue = Math.max(min, internalMin - step * 10);
        }
        else if (e.shiftKey && (e.key === "ArrowRight" || e.key === "ArrowUp")) {
            e.preventDefault();
            newValue = Math.min(internalMax - step, internalMin + step * 10);
        }
        if (newValue !== null) {
            setInternalMin(newValue);
            debouncedUpdate(newValue, internalMax);
        }
    };
    const handleMaxKeyDown = (e) => {
        let newValue = null;
        if (e.key === "Home") {
            e.preventDefault();
            newValue = internalMin + step;
        }
        else if (e.key === "End") {
            e.preventDefault();
            newValue = max;
        }
        else if (e.shiftKey && (e.key === "ArrowLeft" || e.key === "ArrowDown")) {
            e.preventDefault();
            newValue = Math.max(internalMin + step, internalMax - step * 10);
        }
        else if (e.shiftKey && (e.key === "ArrowRight" || e.key === "ArrowUp")) {
            e.preventDefault();
            newValue = Math.min(max, internalMax + step * 10);
        }
        if (newValue !== null) {
            setInternalMax(newValue);
            debouncedUpdate(internalMin, newValue);
        }
    };
    // Calculate filled track position
    const minPercent = ((internalMin - min) / (max - min)) * 100;
    const maxPercent = ((internalMax - min) / (max - min)) * 100;
    return (React.createElement("div", { className: clsx("seekora-range-slider", rangeSliderTheme.root, className), style: style },
        label && (React.createElement("label", { className: clsx("seekora-range-slider__label", rangeSliderTheme.label) }, label)),
        React.createElement("div", { className: clsx("seekora-range-slider__track", rangeSliderTheme.slider) },
            React.createElement("div", { className: clsx("seekora-range-slider__track-bg", rangeSliderTheme.track) }),
            React.createElement("div", { className: clsx("seekora-range-slider__fill", rangeSliderTheme.trackFilled), style: {
                    left: `${minPercent}%`,
                    width: `${maxPercent - minPercent}%`,
                } }),
            React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMin, onChange: handleMinChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMinKeyDown, tabIndex: 0, "aria-valuenow": internalMin, "aria-valuemin": min, "aria-valuemax": max, className: clsx("seekora-range-slider__thumb", rangeSliderTheme.thumb), "aria-label": `Minimum ${label || field}` }),
            React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMax, onChange: handleMaxChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMaxKeyDown, tabIndex: 0, "aria-valuenow": internalMax, "aria-valuemin": min, "aria-valuemax": max, className: clsx("seekora-range-slider__thumb", rangeSliderTheme.thumb), "aria-label": `Maximum ${label || field}` })),
        showValues && (React.createElement("div", { className: clsx("seekora-range-slider__values", rangeSliderTheme.values) },
            React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMin)),
            React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMax))))));
};
