import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// (C) 2021-2026 GoodData Corporation
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
import { isFocusVisible } from "@react-aria/interactions";
import cx from "classnames";
import { defaultImport } from "default-import";
import { FormattedMessage, useIntl } from "react-intl";
import DefaultMeasure from "react-measure";
import { Bubble, BubbleHoverTrigger, Message, UiButton, UiTooltip, makeHorizontalKeyboardNavigation, } from "@gooddata/sdk-ui-kit";
import { applyFilterContextWorkingSelection } from "../../../model/commands/filters.js";
import { isDashboardFilterContextSelectionReset, isDashboardFilterContextWorkingSelectionApplied, } from "../../../model/events/filters.js";
import { useDashboardEventsContext } from "../../../model/react/DashboardEventsContext.js";
import { useDashboardDispatch, useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
import { selectEnableFilterViews, selectIsApplyFiltersAllAtOnceEnabledAndSet, selectLocale, } from "../../../model/store/config/configSelectors.js";
import { selectIsInEditMode } from "../../../model/store/renderMode/renderModeSelectors.js";
import { selectIsWorkingFilterContextChanged, selectNamesOfFiltersWithInvalidSelection, } from "../../../model/store/tabs/filterContext/filterContextSelectors.js";
import { BulletsBar as FlexibleBulletsBar } from "../../flexibleLayout/dragAndDrop/Resize/BulletsBar.js";
import { IntlWrapper } from "../../localization/IntlWrapper.js";
import { FilterViews } from "./filterViews/FilterViews.js";
import { useFilterBarState } from "./hooks/useFilterBarState.js";
import { useFilterExpansionByDragAndDrop } from "./hooks/useFilterExpansionByDragAndDrop.js";
import { useRowsCalculator } from "./hooks/useRowsCalculator.js";
import { ShowAllFiltersButton } from "./ShowAllFiltersButton.js";
import { useExecutionTimestampMessage } from "./useExecutionTimestampMessage.js";
// There are known compatibility issues between CommonJS (CJS) and ECMAScript modules (ESM).
// In ESM, default exports of CJS modules are wrapped in default properties instead of being exposed directly.
// https://github.com/microsoft/TypeScript/issues/52086#issuecomment-1385978414
const Measure = defaultImport(DefaultMeasure);
function DefaultFilterBarContainerCore({ children }) {
    const { rows, height, isFilterBarExpanded, scrollable, setFilterBarExpanded, setCalculatedRows } = useFilterBarState();
    const dropRef = useFilterExpansionByDragAndDrop(rows.length > 1, isFilterBarExpanded, setFilterBarExpanded);
    const isFilterViewsFeatureFlagEnabled = useDashboardSelector(selectEnableFilterViews);
    const isWorkingFilterContextChanged = useDashboardSelector(selectIsWorkingFilterContextChanged);
    const isApplyAllAtOnceEnabledAndSet = useDashboardSelector(selectIsApplyFiltersAllAtOnceEnabledAndSet);
    const filtersWithInvalidSelection = useDashboardSelector(selectNamesOfFiltersWithInvalidSelection);
    const hasInvalidFilterSelections = filtersWithInvalidSelection.length > 0;
    const isInEditMode = useDashboardSelector(selectIsInEditMode);
    const { showExecutionTimestampMessage, formattedDate, onShowCurrentTimestampDashboard } = useExecutionTimestampMessage();
    const dispatch = useDashboardDispatch();
    const applyAllDashboardFilters = useCallback(() => {
        dispatch(applyFilterContextWorkingSelection());
    }, [dispatch]);
    const configurationStyle = useMemo(() => ({
        alignItems: isApplyAllAtOnceEnabledAndSet ? "center" : undefined,
        paddingRight: isApplyAllAtOnceEnabledAndSet ? "10px" : undefined,
    }), [isApplyAllAtOnceEnabledAndSet]);
    const intl = useIntl();
    const [expandedAutomatically, setExpandedAutomatically] = useState(false);
    const onContainerFocus = useCallback(() => {
        // detect if event is mouse
        if (!isFocusVisible()) {
            return;
        }
        setFilterBarExpanded(true);
        setExpandedAutomatically(true);
    }, [setFilterBarExpanded]);
    const onContainerBlur = useCallback(() => {
        if (isFocusVisible() && expandedAutomatically) {
            setFilterBarExpanded(false);
            setExpandedAutomatically(false);
        }
    }, [setFilterBarExpanded, expandedAutomatically]);
    const bubbleText = hasInvalidFilterSelections
        ? intl.formatMessage({ id: "filterBar.invalidFilterSelection" }, { names: filtersWithInvalidSelection.join(", ") })
        : intl.formatMessage({ id: "filterBar.applyFilters" });
    return (_jsxs(_Fragment, { children: [
            _jsxs("div", { className: "dash-filters-wrapper s-gd-dashboard-filter-bar", ref: dropRef, onFocus: onContainerFocus, onBlur: onContainerBlur, children: [
                    _jsxs("div", { style: { height }, className: cx("dash-filters-visible", {
                            scrollable: scrollable,
                            "s-dash-filters-visible-all": isFilterBarExpanded,
                            "apply-all-at-once": isApplyAllAtOnceEnabledAndSet,
                        }), children: [
                            _jsx(AllFiltersContainer, { setCalculatedRows: setCalculatedRows, isAutoExpanded: expandedAutomatically, children: children }), _jsx(FiltersRows, { rows: rows }), _jsxs("div", { className: "filter-bar-configuration", style: configurationStyle, children: [isApplyAllAtOnceEnabledAndSet && isWorkingFilterContextChanged ? (_jsx(UiTooltip, { content: bubbleText, triggerBy: ["hover", "focus"], disabled: !bubbleText, anchor: _jsx(UiButton, { accessibilityConfig: {
                                                ariaHaspopup: "dialog",
                                                ariaLabel: bubbleText,
                                            }, label: intl.formatMessage({ id: "apply" }), variant: "primary", onClick: applyAllDashboardFilters, isDisabled: hasInvalidFilterSelections }) })) : null, isFilterViewsFeatureFlagEnabled ? _jsx(FilterViews, {}) : null] })
                        ] }), _jsx(ShowAllFiltersButton, { isFilterBarExpanded: isFilterBarExpanded, isVisible: rows.length > 1, onToggle: (isExpanded) => setFilterBarExpanded(isExpanded) }), isInEditMode ? _jsx(FlexibleBulletsBar, {}) : null] }), isWorkingFilterContextChanged && isApplyAllAtOnceEnabledAndSet ? (_jsx("div", { "aria-hidden": "true", className: "filters-message", style: { marginTop: rows.length > 1 ? "35px" : "10px" }, children: _jsx(Message, { type: "progress", children: _jsx(FormattedMessage, { id: "filterBar.unappliedFiltersNotification", values: {
                            link: (chunks) => (_jsx("strong", { children: _jsxs(BubbleHoverTrigger, { showDelay: 100, hideDelay: 0, children: [
                                        _jsx(UiButton, { variant: "link", onClick: applyAllDashboardFilters, label: chunks, isDisabled: hasInvalidFilterSelections }), hasInvalidFilterSelections ? (_jsx(Bubble, { children: bubbleText })) : null] }) })),
                        } }) }) })) : null, showExecutionTimestampMessage ? (_jsx("div", { className: "filters-message", style: { marginTop: rows.length > 1 ? "35px" : "10px" }, children: _jsxs(Message, { type: "progress", children: [_jsx(FormattedMessage, { id: "filterBar.executionTimestampNotificationMessage", values: {
                                bold: (chunks) => _jsx("strong", { children: chunks }),
                                date: formattedDate,
                            } }), _jsx("span", { className: "filters-message-spacer" }), _jsx(FormattedMessage, { id: "filterBar.executionTimestampNotificationAction", values: {
                                link: (chunks) => _jsx("a", { onClick: onShowCurrentTimestampDashboard, children: chunks }),
                            } })] }) })) : null] }));
}
function AllFiltersContainer({ setCalculatedRows, isAutoExpanded, children, }) {
    const ref = useRef(null);
    const rowCalculator = useRowsCalculator(ref);
    const prevDimensions = useRef(null);
    const handleResize = useCallback((dimensions) => {
        const areBoundsEqual = (prevBounds, currentBounds) => {
            return (prevBounds?.width === currentBounds?.width && prevBounds?.height === currentBounds?.height);
        };
        // Only call setCalculatedRows when dimensions actually change
        if (!prevDimensions.current ||
            !areBoundsEqual(prevDimensions.current.bounds, dimensions.bounds)) {
            setCalculatedRows(rowCalculator(dimensions));
            prevDimensions.current = dimensions;
        }
    }, [rowCalculator, setCalculatedRows]);
    return (_jsx(Measure, { bounds: true, innerRef: (rf) => {
            ref.current = rf;
        }, onResize: handleResize, children: ({ measureRef }) => (_jsx(MeasuredDiv, { measureRef: measureRef, isAutoExpanded: isAutoExpanded, children: children })) }));
}
function MeasuredDiv({ measureRef, isAutoExpanded, children, }) {
    const containerRef = useRef(null);
    const [activeFilterIndex, setActiveFilterIndex] = useState(null);
    const { registerHandler, unregisterHandler } = useDashboardEventsContext();
    // Focus management: Move focus to filter region when reset/apply event occurs
    const moveToFilterRegion = useCallback(() => {
        const filterRegion = containerRef.current;
        if (filterRegion) {
            filterRegion.focus();
        }
    }, []);
    // Listen for filter context working selection reset/apply events
    useEffect(() => {
        const handler = {
            eval: (event) => isDashboardFilterContextSelectionReset(event) ||
                isDashboardFilterContextWorkingSelectionApplied(event),
            handler: () => {
                moveToFilterRegion();
            },
        };
        registerHandler(handler);
        return () => unregisterHandler(handler);
    }, [registerHandler, unregisterHandler, moveToFilterRegion]);
    const getActiveIndexAndFilterElements = () => {
        const filterElements = containerRef.current
            ? Array.from(containerRef.current.querySelectorAll('button, [tabindex]:not([tabindex="-1"])'))
            : [];
        const activeIndex = filterElements.findIndex((el) => el === document.activeElement);
        return { activeIndex, filterElements };
    };
    // Handle arrow/tab key logic
    const horizontalKeyboardNavigation = makeHorizontalKeyboardNavigation({
        onFocusNext: () => {
            const { activeIndex, filterElements } = getActiveIndexAndFilterElements();
            const next = (activeIndex + 1) % filterElements.length;
            filterElements[next]?.focus();
            setActiveFilterIndex(next);
        },
        onFocusPrevious: () => {
            const { activeIndex, filterElements } = getActiveIndexAndFilterElements();
            const prev = (activeIndex - 1 + filterElements.length) % filterElements.length;
            filterElements[prev]?.focus();
            setActiveFilterIndex(prev);
        },
        onFocusFirst: () => {
            const { filterElements } = getActiveIndexAndFilterElements();
            filterElements[0]?.focus();
            setActiveFilterIndex(0);
        },
        onFocusLast: () => {
            const { filterElements } = getActiveIndexAndFilterElements();
            filterElements[filterElements.length - 1]?.focus();
            setActiveFilterIndex(filterElements.length - 1);
        },
        onUnhandledKeyDown(e) {
            if (e.key === "Tab") {
                const { filterElements } = getActiveIndexAndFilterElements();
                if (activeFilterIndex === -1) {
                    // First tab into bar: focus first filter
                    e.preventDefault();
                    filterElements[0]?.focus();
                }
                else {
                    // move away from filter bar to next/previous element
                    // by letting the event bubble up to the browser with focus moved to the edge of container already
                    if (e.shiftKey) {
                        const first = filterElements[0];
                        first?.focus();
                    }
                    else {
                        const last = filterElements.length - 1;
                        filterElements[last]?.focus();
                    }
                }
            }
        },
    });
    // Don't steal arrow keys from focused editable elements (e.g. inputs in filter
    // dropdowns rendered via portals — events still bubble through the React tree).
    // Use `closest` so we also skip composite controls (combobox/textbox roles, custom
    // numeric inputs, etc.) that wrap a real input deeper in the subtree, and respect
    // a downstream handler that has already dealt with the key.
    const keyboardNavigation = (e) => {
        if (e.defaultPrevented) {
            return;
        }
        const target = e.target;
        if (target.closest('input, textarea, select, [contenteditable="true"], [role="textbox"], [role="combobox"], [role="searchbox"], [role="spinbutton"]')) {
            return;
        }
        horizontalKeyboardNavigation(e);
    };
    const setRefs = useCallback((node) => {
        measureRef(node);
        containerRef.current = node;
    }, [measureRef]);
    const intl = useIntl();
    const regionLabel = isAutoExpanded
        ? `${intl.formatMessage({ id: "filterBar.label" })}. ${intl.formatMessage({ id: "filterBar.filterListAutoExpanded" })}`
        : intl.formatMessage({ id: "filterBar.label" });
    return (_jsx("div", { className: "dash-filters-all", role: "region", "aria-label": regionLabel, tabIndex: -1, ref: setRefs, onKeyDown: keyboardNavigation, children: children }));
}
function FiltersRows({ rows }) {
    return (_jsx(_Fragment, { children: rows.length > 1 && (_jsx("div", { className: "dash-filters-rows", children: rows.map((height, index) => (_jsx("div", { className: "dash-filters-row", style: { height } }, index))) })) }));
}
/**
 * @internal
 */
export function DefaultFilterBarContainer({ children }) {
    const locale = useDashboardSelector(selectLocale);
    return (_jsx(IntlWrapper, { locale: locale, children: _jsx(DefaultFilterBarContainerCore, { children: children }) }));
}
//# sourceMappingURL=DefaultFilterBarContainer.js.map