import Dropdown from "../Dropdown/Dropdown";
import FieldType from "../Types/FieldType";
import FilterOperator from "./Types/FilterOperator";
import OperatorSelector from "./OperatorSelector";
import Includes from "../../../Types/BaseDatabase/Includes";
import IncludesAll from "../../../Types/BaseDatabase/IncludesAll";
import IncludesNone from "../../../Types/BaseDatabase/IncludesNone";
import IsNull from "../../../Types/BaseDatabase/IsNull";
import NotNull from "../../../Types/BaseDatabase/NotNull";
import React, { useEffect, useState } from "react";
const ENTITY_ARRAY_OPERATORS = [
    FilterOperator.HasAnyOf,
    FilterOperator.HasAllOf,
    FilterOperator.HasNoneOf,
    FilterOperator.IsEmpty,
    FilterOperator.IsNotEmpty,
];
const ENTITY_OPERATORS = [
    FilterOperator.Is,
    FilterOperator.IsNot,
    FilterOperator.IsEmpty,
    FilterOperator.IsNotEmpty,
];
const detectArrayState = (rawValue) => {
    if (rawValue instanceof IncludesAll) {
        return {
            operator: FilterOperator.HasAllOf,
            values: rawValue.values.map((v) => {
                return v.toString();
            }),
        };
    }
    if (rawValue instanceof IncludesNone) {
        return {
            operator: FilterOperator.HasNoneOf,
            values: rawValue.values.map((v) => {
                return v.toString();
            }),
        };
    }
    if (rawValue instanceof Includes) {
        return {
            operator: FilterOperator.HasAnyOf,
            values: rawValue.values.map((v) => {
                return v.toString();
            }),
        };
    }
    if (Array.isArray(rawValue)) {
        return {
            operator: FilterOperator.HasAnyOf,
            values: rawValue.map((v) => {
                return v.toString();
            }),
        };
    }
    if (rawValue instanceof IsNull) {
        return { operator: FilterOperator.IsEmpty, values: [] };
    }
    if (rawValue instanceof NotNull) {
        return { operator: FilterOperator.IsNotEmpty, values: [] };
    }
    return { operator: FilterOperator.HasAnyOf, values: [] };
};
const detectSingleState = (rawValue) => {
    if (rawValue instanceof IsNull) {
        return { operator: FilterOperator.IsEmpty, values: [] };
    }
    if (rawValue instanceof NotNull) {
        return { operator: FilterOperator.IsNotEmpty, values: [] };
    }
    if (typeof rawValue === "string" && rawValue) {
        return { operator: FilterOperator.Is, values: [rawValue] };
    }
    return { operator: FilterOperator.Is, values: [] };
};
const buildArrayValue = (state) => {
    switch (state.operator) {
        case FilterOperator.HasAllOf:
            return state.values.length > 0
                ? new IncludesAll(state.values)
                : undefined;
        case FilterOperator.HasNoneOf:
            return state.values.length > 0
                ? new IncludesNone(state.values)
                : undefined;
        case FilterOperator.HasAnyOf:
            return state.values.length > 0 ? state.values : undefined;
        case FilterOperator.IsEmpty:
            return new IsNull();
        case FilterOperator.IsNotEmpty:
            return new NotNull();
        default:
            return undefined;
    }
};
const buildSingleValue = (state) => {
    switch (state.operator) {
        case FilterOperator.Is:
            return state.values[0] || undefined;
        case FilterOperator.IsNot:
            // Use IncludesNone with single-item array to represent "is not".
            return state.values[0] ? new IncludesNone([state.values[0]]) : undefined;
        case FilterOperator.IsEmpty:
            return new IsNull();
        case FilterOperator.IsNotEmpty:
            return new NotNull();
        default:
            return undefined;
    }
};
const EntityFilter = (props) => {
    var _a;
    const filter = props.filter;
    if (filter.type !== FieldType.Entity &&
        filter.type !== FieldType.EntityArray) {
        return React.createElement(React.Fragment, null);
    }
    if (!filter.filterDropdownOptions) {
        return React.createElement(React.Fragment, null);
    }
    const isArray = filter.type === FieldType.EntityArray;
    const detectedState = isArray
        ? detectArrayState(props.filterData[filter.key])
        : detectSingleState(props.filterData[filter.key]);
    /*
     * Hold the operator locally so the user's choice persists even when no
     * values are selected yet (otherwise `buildArrayValue` would return
     * undefined, filterData wouldn't carry the operator, and the next render
     * would reset back to the default).
     */
    const [localOperator, setLocalOperator] = useState(detectedState.operator);
    /*
     * When the external filter data changes and can unambiguously tell us
     * which operator it represents, sync local state.
     */
    useEffect(() => {
        const raw = props.filterData[filter.key];
        if (raw !== undefined && raw !== null) {
            setLocalOperator(detectedState.operator);
        }
        /*
         * Intentionally only re-run when the underlying filter data reference
         * changes — not on every detectedState re-computation.
         */
    }, [props.filterData[filter.key]]);
    const operator = localOperator;
    const state = Object.assign(Object.assign({}, detectedState), { operator });
    const valuelessOperator = operator === FilterOperator.IsEmpty ||
        operator === FilterOperator.IsNotEmpty;
    const dropdownValues = ((_a = filter.filterDropdownOptions) === null || _a === void 0 ? void 0 : _a.filter((option) => {
        return state.values.includes(option.value.toString());
    })) || [];
    const apply = (nextState) => {
        var _a;
        if (!filter.key) {
            return;
        }
        setLocalOperator(nextState.operator);
        const next = Object.assign({}, props.filterData);
        const built = isArray
            ? buildArrayValue(nextState)
            : buildSingleValue(nextState);
        if (built === undefined) {
            delete next[filter.key];
        }
        else {
            next[filter.key] = built;
        }
        (_a = props.onFilterChanged) === null || _a === void 0 ? void 0 : _a.call(props, next);
    };
    return (React.createElement("div", { className: "flex gap-2 items-start" },
        React.createElement(OperatorSelector, { value: operator, options: isArray ? ENTITY_ARRAY_OPERATORS : ENTITY_OPERATORS, onChange: (nextOperator) => {
                apply(Object.assign(Object.assign({}, state), { operator: nextOperator }));
            } }),
        !valuelessOperator && (React.createElement("div", { className: "flex-1 min-w-0" },
            React.createElement(Dropdown, { options: filter.filterDropdownOptions, onChange: (value) => {
                    if (!value || (Array.isArray(value) && value.length === 0)) {
                        apply(Object.assign(Object.assign({}, state), { values: [] }));
                        return;
                    }
                    const nextValues = Array.isArray(value)
                        ? value.map((v) => {
                            return v.toString();
                        })
                        : [value.toString()];
                    apply(Object.assign(Object.assign({}, state), { values: nextValues }));
                }, value: dropdownValues, isMultiSelect: isArray, placeholder: `Filter by ${filter.title}`, className: "relative rounded-md w-full overflow-visible" })))));
};
export default EntityFilter;
//# sourceMappingURL=EntityFilter.js.map