import Button, { ButtonSize, ButtonStyleType } from "../Button/Button";
import Dropdown from "../Dropdown/Dropdown";
import Input, { InputType } from "../Input/Input";
import IconProp from "../../../Types/Icon/IconProp";
import React, { useEffect, useState, } from "react";
import AutocompleteTextInput from "../AutocompleteTextInput/AutocompleteTextInput";
import FieldLabelElement from "../Forms/Fields/FieldLabel";
import { DICTIONARY_FILTER_OPERATOR_OPTIONS, DictionaryFilterOperator, buildDictionaryValue, detectOperatorFromValue, getOperatorOption, } from "./DictionaryFilterOperator";
export var ValueType;
(function (ValueType) {
    ValueType["Text"] = "Text";
    ValueType["Number"] = "Number";
    ValueType["Boolean"] = "Boolean";
})(ValueType || (ValueType = {}));
const DictionaryForm = (props) => {
    const valueTypes = props.valueTypes && props.valueTypes.length > 0
        ? props.valueTypes
        : [ValueType.Text];
    const dropdownOptionsForValueTypes = valueTypes.map((valueType) => {
        return {
            label: valueType,
            value: valueType,
        };
    });
    const [data, setData] = useState([]);
    const [isInitialValueSet, setIsInitialValueSet] = useState(false);
    const updateData = (json) => {
        const newData = Object.keys(json).map((key) => {
            // check if the value type is in data
            var _a;
            const valueTypeInData = (_a = data.find((item) => {
                return item.key === key;
            })) === null || _a === void 0 ? void 0 : _a.type;
            let valueType = valueTypeInData || ValueType.Text;
            const rawEntry = json[key];
            if (!valueTypeInData) {
                if (typeof rawEntry === "number") {
                    valueType = ValueType.Number;
                }
                if (typeof rawEntry === "boolean") {
                    valueType = ValueType.Boolean;
                }
            }
            const detected = detectOperatorFromValue(rawEntry);
            /*
             * Restore typed values (number/boolean) for the form input from
             * the stringified raw representation when the column type allows.
             */
            let restoredValue = detected.rawValue;
            if (valueType === ValueType.Number && detected.rawValue !== "") {
                const parsed = Number(detected.rawValue);
                restoredValue = isNaN(parsed) ? detected.rawValue : parsed;
            }
            else if (valueType === ValueType.Boolean) {
                if (typeof rawEntry === "boolean") {
                    restoredValue = rawEntry;
                }
                else if (detected.rawValue.toLowerCase() === "true") {
                    restoredValue = true;
                }
                else if (detected.rawValue.toLowerCase() === "false") {
                    restoredValue = false;
                }
            }
            return {
                key: key,
                value: restoredValue,
                type: valueType,
                operator: detected.operator,
            };
        });
        setData(newData);
    };
    useEffect(() => {
        if (props.initialValue &&
            !isInitialValueSet &&
            Object.keys(props.initialValue).length > 0) {
            setIsInitialValueSet(true);
            updateData(props.initialValue);
        }
    }, [props.initialValue]);
    const onDataChange = (data) => {
        const result = {};
        data.forEach((item) => {
            var _a;
            /*
             * Non-text types skip the operator system — the existing
             * numeric/boolean inputs always represent equality.
             */
            if (item.type === ValueType.Number) {
                result[item.key] = item.value;
                return;
            }
            if (item.type === ValueType.Boolean) {
                result[item.key] = item.value;
                return;
            }
            const operatorOption = getOperatorOption(item.operator);
            if (operatorOption.hidesValueInput) {
                result[item.key] = buildDictionaryValue({
                    operator: item.operator,
                    rawValue: "",
                });
                return;
            }
            result[item.key] = buildDictionaryValue({
                operator: item.operator,
                rawValue: String((_a = item.value) !== null && _a !== void 0 ? _a : ""),
            });
        });
        if (props.onChange) {
            props.onChange(result);
        }
    };
    const trueDropdownOption = {
        label: "True",
        value: "True",
    };
    const falseDropdownOption = {
        label: "False",
        value: "False",
    };
    const getDefaultValueForType = (type) => {
        if (type === ValueType.Boolean) {
            return true;
        }
        return "";
    };
    const operatorDropdownOptions = DICTIONARY_FILTER_OPERATOR_OPTIONS.map((option) => {
        return {
            label: option.symbol,
            value: option.operator,
        };
    });
    return (React.createElement("div", null,
        React.createElement("div", null,
            data.map((item, index) => {
                var _a, _b;
                const operatorOption = getOperatorOption(item.operator);
                const showOperatorSelector = Boolean(props.enableOperators);
                const hideValueInput = Boolean(showOperatorSelector && operatorOption.hidesValueInput);
                const valueColumnClass = showOperatorSelector
                    ? "ml-1 w-2/5"
                    : "ml-1 w-1/2";
                const keyColumnClass = showOperatorSelector
                    ? "mr-1 w-2/5"
                    : "mr-1 w-1/2";
                return (React.createElement("div", { key: index, className: "flex items-start mb-4 last:mb-0" },
                    React.createElement("div", { className: keyColumnClass },
                        React.createElement("div", { className: "mb-1" },
                            React.createElement(FieldLabelElement, { title: "Key", required: true, hideOptionalLabel: true, className: "block text-xs text-gray-500 font-normal flex justify-between" })),
                        React.createElement(AutocompleteTextInput, { value: item.key, placeholder: props.keyPlaceholder, suggestions: props.keys, isLoadingSuggestions: props.isLoadingKeys, loadingMessage: "Loading attributes...", onChange: (value) => {
                                var _a;
                                const newData = [...data];
                                newData[index].key = value;
                                setData(newData);
                                onDataChange(newData);
                                // If this key matches one of the known keys, notify parent to fetch values
                                if (props.onKeySelected && ((_a = props.keys) === null || _a === void 0 ? void 0 : _a.includes(value))) {
                                    props.onKeySelected(value);
                                }
                            } })),
                    showOperatorSelector ? (React.createElement("div", { className: "mr-1 ml-1 w-1/5 min-w-[120px]" },
                        React.createElement("div", { className: "mb-1" },
                            React.createElement(FieldLabelElement, { title: "Operator", required: true, hideOptionalLabel: true, className: "block text-xs text-gray-500 font-normal flex justify-between" })),
                        React.createElement(Dropdown, { value: operatorDropdownOptions.find((option) => {
                                return option.value === item.operator;
                            }), options: operatorDropdownOptions, isMultiSelect: false, onChange: (selectedOption) => {
                                const newOperator = selectedOption ||
                                    DictionaryFilterOperator.EqualTo;
                                const newOperatorOption = getOperatorOption(newOperator);
                                const newData = [...data];
                                newData[index].operator = newOperator;
                                /*
                                 * Reset the value when switching to a value-less
                                 * operator so we don't ship stale text downstream.
                                 */
                                if (newOperatorOption.hidesValueInput) {
                                    newData[index].value = "";
                                }
                                setData(newData);
                                onDataChange(newData);
                            } }))) : (React.createElement("div", { className: "mr-1 ml-1 flex items-center justify-center pt-8" },
                        React.createElement("span", { className: "text-slate-500 text-2xl leading-none" }, "="))),
                    valueTypes.length > 1 && (React.createElement("div", { className: "ml-1 w-1/2" },
                        React.createElement("div", { className: "mb-1" },
                            React.createElement(FieldLabelElement, { title: "Type", hideOptionalLabel: true, required: true, className: "block text-xs text-gray-500 font-normal flex justify-between" })),
                        React.createElement(Dropdown, { value: dropdownOptionsForValueTypes.find((dropdownOption) => {
                                return dropdownOption.value === item.type;
                            }), options: dropdownOptionsForValueTypes, isMultiSelect: false, onChange: (selectedOption) => {
                                const newData = [...data];
                                const newType = selectedOption || valueTypes[0];
                                newData[index].type = newType;
                                newData[index].value = getDefaultValueForType(newType);
                                setData(newData);
                                onDataChange(newData);
                            } }))),
                    React.createElement("div", { className: valueColumnClass },
                        React.createElement("div", { className: "mb-1" },
                            React.createElement(FieldLabelElement, { title: "Value", hideOptionalLabel: true, required: true, className: "block text-xs text-gray-500 font-normal flex justify-between" })),
                        hideValueInput && (React.createElement(Input, { value: "", placeholder: operatorOption.label, disabled: true, onChange: () => {
                                // no-op — IsEmpty/IsNotEmpty have no value
                            } })),
                        !hideValueInput && item.type === ValueType.Text && (React.createElement(AutocompleteTextInput, { value: item.value.toString(), placeholder: operatorOption.expectsNumericValue
                                ? "Number"
                                : props.valuePlaceholder, suggestions: operatorOption.expectsNumericValue
                                ? undefined
                                : item.key && ((_a = props.valueSuggestions) === null || _a === void 0 ? void 0 : _a[item.key])
                                    ? props.valueSuggestions[item.key]
                                    : undefined, isLoadingSuggestions: operatorOption.expectsNumericValue
                                ? false
                                : Boolean(item.key &&
                                    ((_b = props.loadingValueKeys) === null || _b === void 0 ? void 0 : _b.includes(item.key))), loadingMessage: "Loading values...", onChange: (value) => {
                                const newData = [...data];
                                newData[index].value = value;
                                setData(newData);
                                onDataChange(newData);
                                /*
                                 * Let the parent refine value suggestions server-side
                                 * as the user types. Skip numeric operators — those
                                 * have no value suggestions to narrow.
                                 */
                                if (props.onValueSearch &&
                                    item.key &&
                                    !operatorOption.expectsNumericValue) {
                                    props.onValueSearch(item.key, value);
                                }
                            } })),
                        !hideValueInput && item.type === ValueType.Number && (React.createElement(Input, { value: item.value.toString(), placeholder: props.valuePlaceholder, onChange: (value) => {
                                const newData = [...data];
                                if (typeof value === "string" && value.length > 0) {
                                    newData[index].value = parseInt(value);
                                }
                                else {
                                    delete newData[index];
                                }
                                setData(newData);
                                onDataChange(newData);
                            }, type: InputType.NUMBER })),
                        !hideValueInput && item.type === ValueType.Boolean && (React.createElement(Dropdown, { value: item.value === true
                                ? trueDropdownOption
                                : falseDropdownOption, options: [trueDropdownOption, falseDropdownOption], isMultiSelect: false, onChange: (selectedOption) => {
                                const newData = [...data];
                                if (selectedOption === "True") {
                                    newData[index].value = true;
                                }
                                if (selectedOption === "False") {
                                    newData[index].value = false;
                                }
                                setData(newData);
                                onDataChange(newData);
                            } }))),
                    React.createElement("div", { className: "ml-1 flex flex-col justify-end pt-6" },
                        React.createElement(Button, { dataTestId: `delete-${item.key}`, title: "Delete", buttonStyle: ButtonStyleType.ICON, icon: IconProp.Trash, onClick: () => {
                                const newData = [...data];
                                newData.splice(index, 1);
                                setData(newData);
                                onDataChange(newData);
                            } }))));
            }),
            React.createElement("div", { className: "-ml-3 mt-4" },
                React.createElement(Button, { title: `Add ${props.addButtonSuffix || "Item"}`, icon: IconProp.Add, buttonSize: ButtonSize.Small, onClick: () => {
                        setData([
                            ...data,
                            {
                                key: "",
                                value: getDefaultValueForType(valueTypes[0]),
                                type: valueTypes[0],
                                operator: DictionaryFilterOperator.EqualTo,
                            },
                        ]);
                    } })))));
};
export default DictionaryForm;
//# sourceMappingURL=Dictionary.js.map