import { jsxs, jsx } from 'react/jsx-runtime';
import { useState, useCallback } from 'react';
import { inferFilterType, getDefaultOperator, isUnaryOperator, getOperatorsForFilterType, isBetweenOperator } from './Table.filterUtils.js';
import { Button } from '../../core/Button/Button.js';
import { Input } from '../../forms/Input/Input.js';
import '../../forms/Input/Input.theme.js';
import { Select } from '../../forms/Select/Select.js';
import '../../forms/Select/Select.theme.js';
import { Popover } from '../../core/Popover/Popover.js';
import '../../core/Popover/PopoverContext.js';
import '../../core/Popover/PopoverBody.js';
import { FunnelIcon, XMarkIcon, PlusIcon } from '@heroicons/react/24/outline';
import { cn } from '../../../utils/cn.js';

/**
 * Renders the appropriate value input based on resolved filter type and operator
 */
function FilterValueInput({ filter, column, filterType, onValueChange, }) {
    var _a, _b, _c, _d, _e;
    // Unary operators need no value input
    if (isUnaryOperator(filter.operator))
        return null;
    // Between operator needs two inputs
    if (isBetweenOperator(filter.operator)) {
        const betweenValue = Array.isArray(filter.value) ? filter.value : ["", ""];
        const inputType = filterType === "date" ? "date" : "number";
        return (jsxs("div", { className: "flex items-center gap-1 flex-1 min-w-0", children: [jsx(Input, { value: (_a = betweenValue[0]) !== null && _a !== void 0 ? _a : "", onChange: (e) => onValueChange([e.target.value, betweenValue[1]]), placeholder: "Min", size: "sm", type: inputType, className: "flex-1 min-w-0" }), jsx("span", { className: "text-sm text-[var(--color-text-muted)]", children: "\u2013" }), jsx(Input, { value: (_b = betweenValue[1]) !== null && _b !== void 0 ? _b : "", onChange: (e) => onValueChange([betweenValue[0], e.target.value]), placeholder: "Max", size: "sm", type: inputType, className: "flex-1 min-w-0" })] }));
    }
    // Select filter type
    if (filterType === "select" && (column === null || column === void 0 ? void 0 : column.filterOptions)) {
        const selectOptions = column.filterOptions.map((opt) => ({
            id: opt.value,
            label: opt.label,
            value: opt.value,
        }));
        return (jsx(Select, { value: filter.value, onChange: (value) => onValueChange(value), options: selectOptions, size: "sm", className: "flex-1 min-w-0", placeholder: "Select..." }));
    }
    // MultiSelect filter type
    if (filterType === "multiSelect" && (column === null || column === void 0 ? void 0 : column.filterOptions)) {
        const selectOptions = column.filterOptions.map((opt) => ({
            id: opt.value,
            label: opt.label,
            value: opt.value,
        }));
        return (jsx(Select, { value: filter.value, onChange: (value) => onValueChange(value), options: selectOptions, size: "sm", className: "flex-1 min-w-0", placeholder: "Select...", multiple: true }));
    }
    // Date filter type
    if (filterType === "date") {
        return (jsx(Input, { value: String((_c = filter.value) !== null && _c !== void 0 ? _c : ""), onChange: (e) => onValueChange(e.target.value), placeholder: "Select date...", size: "sm", type: "date", className: "flex-1 min-w-0" }));
    }
    // Number filter type
    if (filterType === "number") {
        return (jsx(Input, { value: String((_d = filter.value) !== null && _d !== void 0 ? _d : ""), onChange: (e) => onValueChange(e.target.value), placeholder: "Value...", size: "sm", type: "number", className: "flex-1 min-w-0" }));
    }
    // Default: text input
    return (jsx(Input, { value: String((_e = filter.value) !== null && _e !== void 0 ? _e : ""), onChange: (e) => onValueChange(e.target.value), placeholder: "Filter value...", size: "sm", type: "text", className: "flex-1 min-w-0" }));
}
function TableFilter({ columns, filterConfig, onFilterChange, filterLogic: controlledLogic, onFilterLogicChange, data, className, }) {
    const filterableColumns = columns.filter((col) => col.filterable);
    // Internal filter logic state
    const [internalLogic, setInternalLogic] = useState("and");
    const filterLogic = controlledLogic !== null && controlledLogic !== void 0 ? controlledLogic : internalLogic;
    const handleSetLogic = useCallback((logic) => {
        if (onFilterLogicChange) {
            onFilterLogicChange(logic);
        }
        else {
            setInternalLogic(logic);
        }
    }, [onFilterLogicChange]);
    const [activeFilters, setActiveFilters] = useState(() => {
        if (filterConfig.length > 0) {
            return filterConfig.map((fc, i) => {
                var _a;
                return ({
                    id: fc.id || `filter-${i}`,
                    columnId: fc.columnId,
                    operator: fc.operator || "contains",
                    value: (_a = fc.value) !== null && _a !== void 0 ? _a : "",
                });
            });
        }
        // Auto-show one empty filter row on first open
        const defaultColumn = filterableColumns[0];
        if (!defaultColumn)
            return [];
        const resolvedType = inferFilterType(defaultColumn, data);
        return [
            {
                id: `filter-${Date.now()}`,
                columnId: defaultColumn.id,
                operator: getDefaultOperator(resolvedType),
                value: "",
            },
        ];
    });
    if (filterableColumns.length === 0)
        return null;
    const columnOptions = filterableColumns.map((col) => ({
        id: col.id,
        label: typeof col.header === "string" ? col.header : col.id,
        value: col.id,
    }));
    const getSelectedColumn = (columnId) => filterableColumns.find((col) => col.id === columnId);
    const getResolvedFilterType = (column) => {
        if (!column)
            return "text";
        return inferFilterType(column, data);
    };
    const syncFilters = (filters) => {
        const newFilterConfig = filters
            .filter((f) => {
            if (!f.columnId)
                return false;
            // Unary operators are always active
            if (isUnaryOperator(f.operator))
                return true;
            // Non-unary operators need a value
            if (f.value == null || f.value === "")
                return false;
            // Between needs both values
            if (isBetweenOperator(f.operator)) {
                return (Array.isArray(f.value) && f.value[0] !== "" && f.value[1] !== "");
            }
            return true;
        })
            .map((f) => ({
            id: f.id,
            columnId: f.columnId,
            value: f.value,
            operator: f.operator,
        }));
        onFilterChange(newFilterConfig);
    };
    const handleAddFilter = () => {
        const defaultColumn = filterableColumns[0];
        if (!defaultColumn)
            return;
        const resolvedType = getResolvedFilterType(defaultColumn);
        const defaultOp = getDefaultOperator(resolvedType);
        setActiveFilters((prev) => [
            ...prev,
            {
                id: `filter-${Date.now()}`,
                columnId: defaultColumn.id,
                operator: defaultOp,
                value: "",
            },
        ]);
    };
    const handleRemoveFilter = (filterId) => {
        setActiveFilters((prev) => {
            const updated = prev.filter((f) => f.id !== filterId);
            syncFilters(updated);
            return updated;
        });
    };
    const handleFilterColumnChange = (filterId, columnId) => {
        setActiveFilters((prev) => {
            const updated = prev.map((f) => {
                if (f.id !== filterId)
                    return f;
                const newColumn = getSelectedColumn(columnId);
                const newType = getResolvedFilterType(newColumn);
                const newOp = getDefaultOperator(newType);
                return { ...f, columnId, operator: newOp, value: "" };
            });
            syncFilters(updated);
            return updated;
        });
    };
    const handleFilterOperatorChange = (filterId, operator) => {
        setActiveFilters((prev) => {
            const updated = prev.map((f) => {
                if (f.id !== filterId)
                    return f;
                // Reset value when switching to/from between or unary operators
                const wasUnary = isUnaryOperator(f.operator);
                const nowUnary = isUnaryOperator(operator);
                const wasBetween = isBetweenOperator(f.operator);
                const nowBetween = isBetweenOperator(operator);
                let newValue = f.value;
                if (wasUnary !== nowUnary || wasBetween !== nowBetween) {
                    newValue = nowBetween ? ["", ""] : "";
                }
                return { ...f, operator, value: newValue };
            });
            syncFilters(updated);
            return updated;
        });
    };
    const handleFilterValueChange = (filterId, value) => {
        setActiveFilters((prev) => {
            const updated = prev.map((f) => f.id === filterId ? { ...f, value } : f);
            syncFilters(updated);
            return updated;
        });
    };
    const handleClearAll = () => {
        setActiveFilters([]);
        onFilterChange([]);
    };
    const appliedFilterCount = activeFilters.filter((f) => {
        if (!f.columnId)
            return false;
        if (isUnaryOperator(f.operator))
            return true;
        return f.value != null && f.value !== "";
    }).length;
    return (jsxs(Popover, { placement: "bottom-end", offset: 8, closeOnClickOutside: false, children: [jsx(Popover.Trigger, { children: jsxs(Button, { color: "neutral", variant: "outline", "aria-label": "Filter table data", size: "sm", children: [jsx(FunnelIcon, { className: "size-4", "aria-hidden": "true" }), "Filters", appliedFilterCount > 0 && (jsx("span", { className: "ml-1 inline-flex items-center justify-center size-5 rounded-full bg-[var(--color-primary)] text-[var(--color-primary-contrast)] text-sm font-medium", children: appliedFilterCount }))] }) }), jsx(Popover.Body, { className: "p-0 max-w-none", children: jsxs("div", { className: cn("w-[500px] p-3", className), role: "dialog", "aria-labelledby": "table-filter-title", "aria-modal": "true", children: [jsxs("div", { className: "flex items-center justify-between mb-3", children: [jsx("div", { id: "table-filter-title", className: "text-sm uppercase font-bold text-[var(--color-text-placeholder)]", children: "Filters" }), activeFilters.length > 1 && (jsxs("div", { className: "flex items-center gap-0.5 rounded-md bg-[var(--color-background-secondary)] p-0.5", children: [jsx("button", { type: "button", className: cn("px-2.5 py-0.5 text-sm font-medium rounded transition-colors", filterLogic === "and"
                                                ? "bg-[var(--color-background)] text-[var(--color-text-primary)] shadow-sm"
                                                : "text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"), onClick: () => handleSetLogic("and"), children: "AND" }), jsx("button", { type: "button", className: cn("px-2.5 py-0.5 text-sm font-medium rounded transition-colors", filterLogic === "or"
                                                ? "bg-[var(--color-background)] text-[var(--color-text-primary)] shadow-sm"
                                                : "text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"), onClick: () => handleSetLogic("or"), children: "OR" })] }))] }), jsx("div", { className: "-m-1 p-1 space-y-2 max-h-[300px] overflow-y-auto", children: activeFilters.map((filter) => {
                                const selectedColumn = getSelectedColumn(filter.columnId);
                                const resolvedType = getResolvedFilterType(selectedColumn);
                                const operatorOptions = getOperatorsForFilterType(resolvedType);
                                return (jsxs("div", { className: "flex items-center gap-1.5", children: [jsx(Select, { value: filter.columnId, onChange: (value) => handleFilterColumnChange(filter.id, value), options: columnOptions, size: "sm", className: "flex-1 min-w-0" }), jsx(Select, { value: filter.operator, onChange: (value) => handleFilterOperatorChange(filter.id, value), options: operatorOptions, size: "sm", className: "flex-1 min-w-0" }), jsx(FilterValueInput, { filter: filter, column: selectedColumn, filterType: resolvedType, onValueChange: (value) => handleFilterValueChange(filter.id, value) }), jsx(Button, { color: "neutral", variant: "link", size: "sm", iconOnly: true, onClick: () => handleRemoveFilter(filter.id), "aria-label": "Remove filter", className: "text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]", children: jsx(XMarkIcon, { className: "size-4", strokeWidth: 2.5 }) })] }, filter.id));
                            }) }), jsxs("div", { className: "mt-3 flex items-center gap-4", children: [jsxs(Button, { color: "neutral", variant: "link", size: "sm", onClick: handleAddFilter, children: [jsx(PlusIcon, { className: "size-4" }), "Add Filter"] }), activeFilters.length > 0 && (jsx(Button, { color: "neutral", variant: "link", size: "sm", onClick: handleClearAll, children: "Clear All" }))] })] }) })] }));
}

export { TableFilter };
