import ObjectID from "../../../Types/ObjectID";
import useTranslateValue from "../../Utils/Translation";
import React, { useId, useLayoutEffect, useRef, useState, } from "react";
import Color from "../../../Types/Color";
import Select from "react-select";
const Dropdown = (props) => {
    var _a;
    const { translateString } = useTranslateValue();
    const tx = (value) => {
        return translateString(value);
    };
    const uniqueId = useId();
    const errorId = `dropdown-error-${uniqueId}`;
    const isDropdownOptionGroup = (item) => {
        return ("options" in item && Array.isArray(item.options));
    };
    const flatOptions = props.options.flatMap((item) => {
        if (isDropdownOptionGroup(item)) {
            return item.options;
        }
        return [item];
    });
    const getDropdownOptionFromValue = (value) => {
        if (value === undefined) {
            return undefined;
        }
        if (value instanceof ObjectID) {
            value = value.toString();
        }
        if (Array.isArray(value) &&
            value.length > 0 &&
            Object.keys(value[0]).includes("value")) {
            return value;
        }
        if (Array.isArray(value) &&
            value.length > 0 &&
            (typeof value[0] === "string" || typeof value[0] === "number")) {
            const options = [];
            for (const item of value) {
                if (!Array.isArray(item) &&
                    (typeof item === "string" || typeof item === "number")) {
                    const option = flatOptions.find((option) => {
                        return option.value === item;
                    });
                    if (option) {
                        options.push(option);
                    }
                }
            }
            return options;
        }
        if (!Array.isArray(value) &&
            (typeof value === "string" || typeof value === "number")) {
            return flatOptions.find((option) => {
                return option.value === value;
            });
        }
        return value;
    };
    const [value, setValue] = useState(getDropdownOptionFromValue(props.initialValue));
    const firstUpdate = useRef(true);
    const normalizeLabelColor = (color) => {
        if (!color) {
            return undefined;
        }
        if (color instanceof Color) {
            return color.toString();
        }
        if (typeof color === "string" && color.trim().length > 0) {
            return color;
        }
        return undefined;
    };
    const normalizeDropdownLabel = (label) => {
        if (!label) {
            return null;
        }
        const getValueFromModel = (columnName) => {
            if (typeof label.getColumnValue === "function" &&
                typeof label.getTableColumnMetadata === "function") {
                return label.getColumnValue(columnName);
            }
            return label === null || label === void 0 ? void 0 : label[columnName];
        };
        const labelName = (() => {
            const valueFromGetter = getValueFromModel("name");
            if (valueFromGetter && valueFromGetter.trim().length > 0) {
                return valueFromGetter;
            }
            const fallbackName = label === null || label === void 0 ? void 0 : label.name;
            if (fallbackName && fallbackName.trim().length > 0) {
                return fallbackName;
            }
            return undefined;
        })();
        if (!labelName) {
            return null;
        }
        const rawColor = getValueFromModel("color");
        const color = normalizeLabelColor(rawColor) ||
            normalizeLabelColor(label === null || label === void 0 ? void 0 : label.color);
        const idValue = (() => {
            if (typeof label.id !== "undefined") {
                const idFromGetter = label.id;
                if (idFromGetter) {
                    return idFromGetter.toString();
                }
            }
            const fallbackId = (label === null || label === void 0 ? void 0 : label._id) || (label === null || label === void 0 ? void 0 : label.id);
            if (fallbackId) {
                return fallbackId;
            }
            return undefined;
        })();
        const normalized = {
            name: labelName,
        };
        if (idValue) {
            normalized.id = idValue;
        }
        if (color) {
            normalized.color = color;
        }
        return normalized;
    };
    const normalizeLabelCollection = (labels) => {
        if (!labels || labels.length === 0) {
            return [];
        }
        return labels
            .map((label) => {
            return normalizeDropdownLabel(label);
        })
            .filter((label) => {
            return label !== null;
        });
    };
    const renderOptionColorIndicator = (color) => {
        const normalizedColor = color
            ? new Color(color).toString()
            : undefined;
        if (!normalizedColor) {
            return null;
        }
        return (React.createElement("span", { "aria-hidden": "true", className: "h-2.5 w-2.5 flex-none rounded-full border border-gray-200", style: {
                backgroundColor: normalizedColor,
            }, title: normalizedColor }));
    };
    const getLabelStyle = (color) => {
        if (!color) {
            return {
                backgroundColor: "#e5e7eb", // gray-200
                color: "#374151", // gray-700
            };
        }
        try {
            const parsedColor = Color.fromString(color);
            return {
                backgroundColor: parsedColor.toString(),
                color: Color.shouldUseDarkText(parsedColor)
                    ? "#111827" // gray-900
                    : "#f9fafb", // gray-50
            };
        }
        catch (_a) {
            return {
                backgroundColor: color,
                color: "#111827",
            };
        }
    };
    const defaultSelectedLabelAccentColor = "#6366f1"; // indigo-500
    const resolveSelectedLabelColor = (color) => {
        if (!color) {
            return defaultSelectedLabelAccentColor;
        }
        try {
            return Color.fromString(color).toString();
        }
        catch (_a) {
            return defaultSelectedLabelAccentColor;
        }
    };
    const renderAssociatedLabels = (labels, context, hiddenLabelCount) => {
        if (labels.length === 0 && hiddenLabelCount === 0) {
            return null;
        }
        if (context === "value") {
            return (React.createElement("div", { className: "flex flex-wrap items-center gap-1" },
                labels.map((label, index) => {
                    const accentColor = resolveSelectedLabelColor(label.color);
                    return (React.createElement("span", { key: `${label.id || label.name}-selected-${index}`, className: "inline-flex items-center gap-1 rounded-full border border-gray-200 bg-white px-2 py-0.5 text-xs font-medium text-gray-600", style: {
                            borderColor: accentColor,
                        }, title: label.name },
                        React.createElement("span", { "aria-hidden": "true", className: "h-1.5 w-1.5 rounded-full", style: {
                                backgroundColor: accentColor,
                            } }),
                        label.name));
                }),
                hiddenLabelCount > 0 ? (React.createElement("span", { className: "inline-flex items-center rounded-full border border-gray-200 bg-white px-2 py-0.5 text-xs font-medium text-gray-500" },
                    "+",
                    hiddenLabelCount)) : null));
        }
        return (React.createElement("div", { className: "flex flex-wrap gap-1" },
            labels.map((label, index) => {
                const { backgroundColor, color } = getLabelStyle(label.color);
                return (React.createElement("span", { key: `${label.id || label.name}-menu-${index}`, className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium shadow-sm", style: { backgroundColor, color } }, label.name));
            }),
            hiddenLabelCount > 0 ? (React.createElement("span", { className: "inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600" },
                "+",
                hiddenLabelCount)) : null));
    };
    const formatDropdownOptionLabel = (option, meta) => {
        var _a, _b, _c;
        const normalizedLabels = normalizeLabelCollection(option.labels);
        const maxVisibleLabels = meta.context === "menu" ? 4 : 2;
        const visibleLabels = normalizedLabels.slice(0, maxVisibleLabels);
        const hiddenLabelCount = Math.max(normalizedLabels.length - visibleLabels.length, 0);
        if (meta.context === "value") {
            return (React.createElement("div", { className: "flex flex-wrap items-center gap-2" },
                React.createElement("div", { className: "flex items-center gap-2" },
                    renderOptionColorIndicator(option.color),
                    React.createElement("span", { className: "text-sm font-medium text-gray-900" }, (_a = tx(option.label)) !== null && _a !== void 0 ? _a : option.label)),
                renderAssociatedLabels(visibleLabels, meta.context, hiddenLabelCount)));
        }
        return (React.createElement("div", { className: "flex flex-col gap-1" },
            React.createElement("div", { className: "flex items-center gap-2" },
                renderOptionColorIndicator(option.color),
                React.createElement("span", { className: "text-sm font-medium text-gray-900" }, (_b = tx(option.label)) !== null && _b !== void 0 ? _b : option.label)),
            option.description ? (React.createElement("span", { className: "text-xs text-gray-500" }, (_c = tx(option.description)) !== null && _c !== void 0 ? _c : option.description)) : null,
            renderAssociatedLabels(visibleLabels, meta.context, hiddenLabelCount)));
    };
    useLayoutEffect(() => {
        if (firstUpdate.current && props.initialValue) {
            firstUpdate.current = false;
            return;
        }
        const value = getDropdownOptionFromValue(props.value === null ? undefined : props.value);
        setValue(value);
    }, [props.value]);
    return (React.createElement("div", { id: props.id, className: `${props.className ||
            "relative mt-2 mb-1 rounded-md w-full overflow-visible"}`, onClick: () => {
            var _a, _b;
            (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props);
            (_b = props.onFocus) === null || _b === void 0 ? void 0 : _b.call(props);
        } },
        React.createElement(Select, { classNamePrefix: "ou-select", unstyled: false, formatOptionLabel: formatDropdownOptionLabel, onBlur: () => {
                var _a;
                (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props);
            }, "data-testid": props.dataTestId, tabIndex: props.tabIndex, isMulti: props.isMultiSelect, value: value || null, onFocus: () => {
                var _a;
                (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props);
            }, "aria-label": props.ariaLabel, "aria-invalid": props.error ? true : undefined, "aria-describedby": props.error ? errorId : undefined, classNames: {
                control: (state) => {
                    const classes = [
                        "!min-h-[40px] !rounded-lg !border !bg-white !shadow-sm !transition-all !duration-150",
                        state.isFocused
                            ? "!border-indigo-400 !ring-2 !ring-indigo-100"
                            : "!border-gray-300 hover:!border-indigo-300",
                        state.isDisabled
                            ? "!bg-gray-100 !text-gray-400"
                            : "!cursor-pointer",
                    ];
                    if (props.error) {
                        classes.push("!border-red-400 !ring-2 !ring-red-100");
                    }
                    return classes.join(" ");
                },
                valueContainer: () => {
                    return "!gap-2 !px-2";
                },
                placeholder: () => {
                    return "text-sm text-gray-400";
                },
                input: () => {
                    return "text-sm text-gray-900";
                },
                singleValue: () => {
                    return "text-sm text-gray-900 font-medium";
                },
                indicatorsContainer: () => {
                    return "!gap-1 !px-1";
                },
                dropdownIndicator: () => {
                    return "text-gray-500 transition-colors duration-150 hover:text-indigo-400";
                },
                clearIndicator: () => {
                    return "text-gray-400 transition-colors duration-150 hover:text-red-500";
                },
                menu: () => {
                    return "!mt-2 !rounded-xl !border !border-gray-100 !bg-white !shadow-xl";
                },
                menuList: () => {
                    return "!py-2";
                },
                option: (state) => {
                    if (state.isDisabled) {
                        return "px-3 py-2 text-sm text-gray-300 cursor-not-allowed";
                    }
                    if (state.isSelected) {
                        return "px-3 py-2 text-sm bg-indigo-200 text-indigo-900";
                    }
                    if (state.isFocused) {
                        return "px-3 py-2 text-sm bg-indigo-100 text-indigo-700";
                    }
                    return "px-3 py-2 text-sm text-gray-700";
                },
                group: () => {
                    return "py-1";
                },
                groupHeading: () => {
                    return "px-3 py-2 text-xs font-semibold uppercase tracking-wider text-gray-500";
                },
                noOptionsMessage: () => {
                    return "px-3 py-2 text-sm text-gray-500";
                },
                multiValue: () => {
                    return "flex items-center gap-2 rounded-lg border border-indigo-100 bg-indigo-50 px-2 py-1";
                },
                multiValueLabel: () => {
                    return "flex flex-wrap items-center gap-2 text-sm font-medium text-indigo-900";
                },
                multiValueRemove: () => {
                    return "text-indigo-400 hover:text-indigo-600 transition-colors duration-150";
                },
            }, styles: {
                dropdownIndicator: (provided) => {
                    return Object.assign(Object.assign({}, provided), { padding: 8 });
                },
                clearIndicator: (provided) => {
                    return Object.assign(Object.assign({}, provided), { padding: 8 });
                },
                indicatorSeparator: () => {
                    return {
                        display: "none",
                    };
                },
                option: (provided, state) => {
                    if (state.isSelected) {
                        return Object.assign(Object.assign({}, provided), { backgroundColor: "#c7d2fe", color: "#1e1b4b" });
                    }
                    if (state.isFocused) {
                        return Object.assign(Object.assign({}, provided), { backgroundColor: "#e0e7ff", color: "#312e81" });
                    }
                    return Object.assign(Object.assign({}, provided), { color: "#374151" });
                },
                multiValue: (provided) => {
                    return Object.assign(Object.assign({}, provided), { backgroundColor: "#eef2ff", borderRadius: 8, border: "1px solid #c7d2fe", paddingLeft: 4, paddingRight: 4 });
                },
                multiValueLabel: (provided) => {
                    return Object.assign(Object.assign({}, provided), { color: "#312e81", fontSize: "0.875rem", fontWeight: 500 });
                },
                multiValueRemove: (provided) => {
                    return Object.assign(Object.assign({}, provided), { color: "#6366f1", ":hover": {
                            color: "#4f46e5", // indigo-600
                            backgroundColor: "transparent",
                        } });
                },
                menuPortal: (base) => {
                    return Object.assign(Object.assign({}, base), { zIndex: 50 });
                },
            }, menuPortalTarget: document.body, menuPosition: "fixed", isClearable: true, isSearchable: true, placeholder: (_a = tx(props.placeholder)) !== null && _a !== void 0 ? _a : props.placeholder, options: props.options, onChange: (option) => {
                var _a, _b, _c, _d;
                if (option) {
                    if (props.isMultiSelect) {
                        const value = option;
                        setValue(value);
                        (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, value.map((i) => {
                            return i.value;
                        }));
                    }
                    else {
                        const value = option;
                        setValue(value);
                        (_b = props.onChange) === null || _b === void 0 ? void 0 : _b.call(props, value.value);
                    }
                }
                if (option === null && props.isMultiSelect) {
                    setValue([]);
                    (_c = props.onChange) === null || _c === void 0 ? void 0 : _c.call(props, []);
                }
                if (option === null && !props.isMultiSelect) {
                    setValue(undefined);
                    (_d = props.onChange) === null || _d === void 0 ? void 0 : _d.call(props, null);
                }
            } }),
        props.error && (React.createElement("p", { id: errorId, "data-testid": "error-message", className: "mt-1 text-sm text-red-400", role: "alert" }, props.error))));
};
export default Dropdown;
//# sourceMappingURL=Dropdown.js.map