import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// (C) 2025-2026 GoodData Corporation
import { useCallback, useEffect, useMemo, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { useDebouncedState } from "@gooddata/sdk-ui";
import { ContentDivider } from "../../../Dialog/ContentDivider.js";
import { Dropdown } from "../../../Dropdown/Dropdown.js";
import { DropdownList } from "../../../Dropdown/DropdownList.js";
import { Message } from "../../../Messages/Message.js";
import { UiButton } from "../../UiButton/UiButton.js";
import { UiChip } from "../../UiChip/UiChip.js";
import { UiAutofocus } from "../../UiFocusManager/UiAutofocus.js";
import { e } from "../asyncTableBem.js";
import { messages } from "../locales.js";
import { FILTER_CHIP_MAX_WIDTH, FILTER_ITEMS_OFFSET, FILTER_OPTION_ALL_VALUE, SCROLLBAR_WIDTH, } from "./constants.js";
import { UiAsyncTableDropdownItem } from "./UiAsyncTableDropdownItem.js";
import { getFilterDropdownId, getFilterOptionsMap } from "./utils.js";
/**
 * @internal
 */
export function UiAsyncTableFilter(props) {
    const intl = useIntl();
    const { filteredOptions, searchValue, isApplyButtonEnabled, labelWithSelected, setSearchValue, onItemClick, isItemSelected, onApplyFactory, onCancelFactory, } = useAsyncTableFilterState(props);
    const { isMultiSelect, isFiltersTooLarge, variant, isMobileView, width, label, onChipReset } = props;
    const isSmall = variant === "small";
    const chipMaxWidth = useMemo(() => {
        if (isSmall && isMobileView && width) {
            return width - SCROLLBAR_WIDTH;
        }
        return isSmall ? FILTER_CHIP_MAX_WIDTH : undefined;
    }, [isSmall, isMobileView, width]);
    const dropdownId = getFilterDropdownId(label);
    const dropdownListId = `${dropdownId}-list`;
    return (_jsx("div", { className: e("filter"), children: _jsx(Dropdown, { renderButton: ({ toggleDropdown, isOpen }) => (_jsx(UiChip, { label: labelWithSelected, maxWidth: chipMaxWidth, isDeletable: !!onChipReset, onDelete: onChipReset, onClick: () => toggleDropdown(), isActive: isOpen, accessibilityConfig: {
                    isExpanded: isOpen,
                    popupId: dropdownId,
                    popupType: "dialog",
                } })), alignPoints: [{ align: "bl tl" }, { align: "tl bl" }], renderBody: ({ closeDropdown }) => (_jsx(UiAutofocus, { children: _jsxs("div", { role: "dialog", id: dropdownId, "aria-label": labelWithSelected, children: [_jsx(DropdownList, { id: dropdownListId, items: filteredOptions, renderItem: ({ item, isFirst }) => (_jsx(UiAsyncTableDropdownItem, { label: item.label ?? String(item.value), secondaryLabel: item.secondaryLabel, onClick: () => onItemClick(item, closeDropdown), isSelected: isItemSelected(item), isMultiSelect: isMultiSelect, isUnderlined: isFirst })), showSearch: true, searchPlaceholder: intl.formatMessage(messages["filterSearchPlaceholder"]), searchString: searchValue, searchFieldSize: "small", onSearch: setSearchValue, containerPadding: FILTER_ITEMS_OFFSET, onKeyDownSelect: (item) => onItemClick(item, closeDropdown), onKeyDownConfirm: onApplyFactory(closeDropdown), closeDropdown: closeDropdown }), isMultiSelect ? (_jsxs("div", { className: e("filter-bottom"), children: [
                                _jsx(ContentDivider, {}), _jsxs("div", { className: e("filter-buttons"), children: [
                                        _jsx(UiButton, { label: intl.formatMessage(messages["filterOptionCancel"]), onClick: onCancelFactory(closeDropdown), variant: "secondary", size: "small" }), _jsx(UiButton, { label: intl.formatMessage(messages["filterOptionApply"]), onClick: onApplyFactory(closeDropdown), variant: "primary", size: "small", isDisabled: !isApplyButtonEnabled })
                                    ] })
                            ] })) : null, isFiltersTooLarge ? (_jsx("div", { className: e("filter-error"), children: _jsx(Message, { type: "error", children: _jsx(FormattedMessage, { id: messages["filterTooLarge"].id, values: {
                                        strong: (chunks) => _jsx("strong", { children: chunks }),
                                    } }) }) })) : null] }) })) }) }));
}
function useAsyncTableFilterState({ options, selected, onItemsSelect, isMultiSelect, label, }) {
    const intl = useIntl();
    const [checkedItems, setCheckedItems] = useState(getFilterOptionsMap(selected ?? []));
    const [searchValue, setSearchValue, debouncedSearchValue] = useDebouncedState("", 300);
    useEffect(() => {
        setCheckedItems(getFilterOptionsMap(selected ?? []));
    }, [selected]);
    const filteredOptions = useMemo(() => {
        const searchLowerCased = debouncedSearchValue.toLowerCase();
        const filteredOptions = options.filter((option) => (option.label ?? "").toLowerCase().includes(searchLowerCased));
        if (isMultiSelect && filteredOptions.length > 0) {
            return [
                {
                    value: FILTER_OPTION_ALL_VALUE,
                    label: intl.formatMessage(messages["filterOptionAll"]),
                    secondaryLabel: `(${options.length})`,
                },
                ...filteredOptions,
            ];
        }
        return filteredOptions;
    }, [options, debouncedSearchValue, isMultiSelect, intl]);
    const isAllSelected = useMemo(() => {
        return checkedItems.size === options.length;
    }, [checkedItems, options]);
    const onSelectAll = useCallback(() => {
        if (isAllSelected) {
            setCheckedItems(new Map());
        }
        else {
            setCheckedItems(getFilterOptionsMap(options));
        }
    }, [options, isAllSelected]);
    const onItemClick = useCallback((item, closeDropdown) => {
        if (isMultiSelect) {
            if (item.value === FILTER_OPTION_ALL_VALUE) {
                onSelectAll();
                return;
            }
            setCheckedItems((prev) => {
                const newCheckedItems = new Map(prev);
                if (newCheckedItems.has(item.value)) {
                    newCheckedItems.delete(item.value);
                }
                else {
                    newCheckedItems.set(item.value, item);
                }
                return newCheckedItems;
            });
        }
        else {
            onItemsSelect([item]);
            closeDropdown();
        }
    }, [onItemsSelect, isMultiSelect, onSelectAll]);
    const isItemSelected = useCallback((item) => {
        if (isMultiSelect) {
            if (item.value === FILTER_OPTION_ALL_VALUE) {
                return isAllSelected;
            }
            return checkedItems.has(item.value);
        }
        return selected?.some((selectedItem) => selectedItem.value === item.value);
    }, [checkedItems, isMultiSelect, isAllSelected, selected]);
    // deep comparison of selected and checked items
    const isApplyButtonEnabled = useMemo(() => {
        const selectedValues = new Set(selected?.map((item) => item.value) || []);
        const checkedValues = new Set(checkedItems.keys());
        if (checkedValues.size === 0) {
            return false;
        }
        if (selectedValues.size !== checkedValues.size) {
            return true;
        }
        for (const value of selectedValues) {
            if (!checkedValues.has(value)) {
                return true;
            }
        }
        return false;
    }, [selected, checkedItems]);
    const labelWithSelected = useMemo(() => {
        let selectedLabels;
        if (selected?.length === options.length) {
            selectedLabels = intl.formatMessage(messages["filterOptionAll"]);
        }
        else {
            selectedLabels = selected?.map((item) => item.label).join(", ");
        }
        return `${label}: ${selectedLabels}`;
    }, [label, selected, options, intl]);
    const onApplyFactory = useCallback((closeDropdown) => () => {
        onItemsSelect(Array.from(checkedItems.values()));
        closeDropdown();
    }, [onItemsSelect, checkedItems]);
    const onCancelFactory = useCallback((closeDropdown) => () => {
        setCheckedItems(getFilterOptionsMap(selected ?? []));
        closeDropdown();
    }, [selected]);
    return {
        filteredOptions,
        searchValue,
        isApplyButtonEnabled,
        labelWithSelected,
        setSearchValue,
        onItemClick,
        isItemSelected,
        onApplyFactory,
        onCancelFactory,
    };
}
