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 cx from "classnames";
import { useIntl } from "react-intl";
import { ItemsWrapper, Overlay, SingleSelectListItem, UiFocusManager, UiIcon, UiIconButton, UiTooltip, findFocusableElementOutsideContainer, getFocusableElements, isActionKey, makeMenuKeyboardNavigation, useId, useIdPrefixed, useMediaQuery, } from "@gooddata/sdk-ui-kit";
import { DEFAULT_MENU_BUTTON_ID } from "../../../_staging/accessibility/elementId.js";
import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
import { selectDashboardDensity } from "../../../model/store/ui/uiSelectors.js";
import { DefaultSubmenuHeader } from "./DefaultSubmenuHeader.js";
const overlayAlignPoints = [{ align: "br tr" }];
/**
 * @alpha
 */
export function DefaultMenuButton({ menuItems }) {
    const [isOpen, setIsOpen] = useState(false);
    const [autofocusSubmenu, setAutofocusSubmenu] = useState(false);
    const intl = useIntl();
    const smallScreen = useMediaQuery("mobileDevice");
    const tooltipText = intl.formatMessage({ id: "controlButtons.options.tooltip" });
    const backLabel = intl.formatMessage({ id: "controlButtons.options.back" });
    const closeLabel = intl.formatMessage({ id: "controlButtons.options.closeMenu" });
    const menuWrapperRef = useRef(null);
    const triggerButtonRef = useRef(null);
    const [parentItemId, setParentItemId] = useState(null);
    const menuItemRefs = useRef(new Map());
    const density = useDashboardSelector(selectDashboardDensity);
    const setMenuItemRef = useCallback((itemId) => (element) => {
        if (element) {
            menuItemRefs.current.set(itemId, element);
        }
        else {
            menuItemRefs.current.delete(itemId);
        }
    }, []);
    // generate unique IDs for accessibility and dropdown positioning
    const id = useId();
    const menuId = `menu-${id}`;
    const dropdownAnchorClassName = `dash-header-options-anchor-${id}`;
    const onMenuButtonClick = useCallback(() => {
        setIsOpen((prevIsOpen) => !prevIsOpen);
        setSelectedMenuItem(null);
    }, []);
    const onClose = useCallback(() => {
        setIsOpen(false);
        setSelectedMenuItem(null);
        setParentItemId(null);
        setAutofocusSubmenu(false);
    }, []);
    const openSubmenu = useCallback((menuItem) => {
        setAutofocusSubmenu(true);
        setParentItemId(menuItem.itemId);
        setSelectedMenuItem(menuItem);
    }, []);
    const closeSubmenu = useCallback(() => {
        //parentItemId is set to null later in effect focusing parent item
        setSelectedMenuItem(null);
        setAutofocusSubmenu(true);
    }, []);
    const [selectedMenuItem, setSelectedMenuItem] = useState(null);
    const visibleMenuItems = useMemo(() => (selectedMenuItem?.items ?? menuItems).filter((item) => item.visible !== false), [menuItems, selectedMenuItem]);
    const menuKeyboardNavigationHandler = makeMenuKeyboardNavigation({
        onFocusFirst: () => {
            if (menuWrapperRef.current) {
                const { firstElement } = getFocusableElements(menuWrapperRef.current);
                firstElement?.focus();
            }
        },
        onFocusNext: () => {
            const elements = Array.from(menuItemRefs.current.values());
            const currentIndex = elements.indexOf(document.activeElement);
            const nextElement = currentIndex === elements.length - 1 ? elements[0] : elements[currentIndex + 1];
            nextElement?.focus();
        },
        onFocusPrevious: () => {
            const elements = Array.from(menuItemRefs.current.values());
            const currentIndex = elements.indexOf(document.activeElement);
            const previousElement = currentIndex <= 0 ? elements[elements.length - 1] : elements[currentIndex - 1];
            previousElement?.focus();
        },
        onClose,
        onLeaveLevel(event) {
            const [_itemId, targetItem] = Array.from(menuItemRefs.current.entries()).find(([_, element]) => element === event.target) ||
                [];
            if (targetItem?.role === "menuitem" && parentItemId) {
                closeSubmenu();
            }
        },
        onEnterLevel(event) {
            const [itemId] = Array.from(menuItemRefs.current.entries()).find(([_, element]) => element === event.target) ||
                [];
            const menuItem = visibleMenuItems.find((item) => item.itemId === itemId);
            if (menuItem?.type === "menu") {
                openSubmenu(menuItem);
            }
        },
        onUnhandledKeyDown(event) {
            if (isActionKey(event)) {
                //onSelect by keyboard is handled by the menu item itself
                return;
            }
            event.stopPropagation();
            event.preventDefault();
            if (event.key !== "Tab") {
                return;
            }
            const triggerButton = triggerButtonRef.current;
            const nextElement = triggerButton
                ? findFocusableElementOutsideContainer(triggerButton, event.shiftKey ? "backward" : "forward")
                : null;
            onClose();
            nextElement?.focus();
        },
    });
    useEffect(() => {
        if (autofocusSubmenu && selectedMenuItem) {
            const firstElement = Array.from(menuItemRefs.current.values())[0];
            firstElement?.focus();
            setAutofocusSubmenu(false);
        }
        if (autofocusSubmenu && !selectedMenuItem && parentItemId) {
            const element = menuItemRefs.current.get(parentItemId);
            if (element) {
                element.focus();
            }
            setAutofocusSubmenu(false);
            setParentItemId(null);
        }
    }, [selectedMenuItem, parentItemId, menuItemRefs, autofocusSubmenu]);
    if (!visibleMenuItems.length) {
        return null;
    }
    const renderMenuItems = () => {
        return (_jsx(Overlay, { alignTo: `.${dropdownAnchorClassName}`, alignPoints: overlayAlignPoints, className: "gd-header-menu-overlay", closeOnMouseDrag: true, closeOnOutsideClick: true, onClose: onMenuButtonClick, children: _jsx(UiFocusManager, { enableAutofocus: true, enableReturnFocusOnUnmount: true, children: _jsx("div", { onKeyDown: menuKeyboardNavigationHandler, children: _jsxs(ItemsWrapper, { smallItemsSpacing: true, className: "gd-menu", wrapperRef: menuWrapperRef, children: [selectedMenuItem ? (_jsx(DefaultSubmenuHeader, { title: selectedMenuItem.itemName, backLabel: backLabel, closeLabel: closeLabel, onClose: onClose, onGoBack: () => {
                                    setAutofocusSubmenu(true);
                                    setSelectedMenuItem(null);
                                } })) : null, _jsx("div", { role: "menu", id: menuId, "aria-labelledby": DEFAULT_MENU_BUTTON_ID, children: visibleMenuItems.map((menuItem) => {
                                    return (_jsx(MenuItem, { menuItem: menuItem, selectedMenuItem: selectedMenuItem, setMenuItemRef: setMenuItemRef, setSelectedMenuItem: setSelectedMenuItem, setParentItemId: setParentItemId, setAutofocusSubmenu: setAutofocusSubmenu, setIsOpen: setIsOpen }, menuItem.itemId));
                                }) })
                        ] }) }) }) }, "topBarMenuButton"));
    };
    return (_jsxs(_Fragment, { children: [
            _jsx("div", { className: cx("dash-header-options-button", dropdownAnchorClassName), children: _jsx(UiTooltip, { arrowPlacement: "top-end", content: tooltipText, anchor: _jsx(UiIconButton, { ref: triggerButtonRef, onClick: onMenuButtonClick, icon: "ellipsis", id: DEFAULT_MENU_BUTTON_ID, dataTestId: "s-header-options-button", variant: smallScreen ? "tertiary" : "secondary", size: smallScreen ? "xlarge" : density === "compact" ? "small" : "medium", accessibilityConfig: {
                            role: "button",
                            ariaLabel: tooltipText,
                            ariaExpanded: isOpen,
                            ariaHaspopup: "menu",
                            ariaControls: isOpen ? menuId : undefined,
                        } }), triggerBy: ["hover", "focus"] }) }), isOpen ? renderMenuItems() : null] }));
}
function MenuItem({ menuItem, selectedMenuItem, setMenuItemRef, setSelectedMenuItem, setParentItemId, setAutofocusSubmenu, setIsOpen, }) {
    const tooltipId = useIdPrefixed(`menu-tooltip-${menuItem.itemId}`);
    const warningTooltipId = useIdPrefixed(`menu-warning-${menuItem.itemId}`);
    // Tracks whether the item-level (focus-triggered) warning tooltip is open, so the icon's hover tooltip can
    // be suppressed while the item is focused - avoids both tooltips showing at once.
    const [isWarningFocusTooltipOpen, setIsWarningFocusTooltipOpen] = useState(false);
    const renderWithOptionalTooltip = (menuItem, children) => {
        const selectorClassName = `gd-menu-item-${menuItem.itemId}`;
        const hasTooltip = !!menuItem.tooltip;
        const element = children({
            selectorClassName,
            tooltipId: hasTooltip ? tooltipId : undefined,
        });
        if (!hasTooltip) {
            return element;
        }
        return (_jsx(UiTooltip, { id: tooltipId, triggerBy: ["hover", "focus"], arrowPlacement: "right", optimalPlacement: true, content: menuItem.tooltip, anchor: element }));
    };
    if (menuItem.type === "separator") {
        return (_jsx(SingleSelectListItem, { type: menuItem.type, className: menuItem.className, accessibilityConfig: {
                role: "separator",
            } }, menuItem.itemId));
    }
    if (menuItem.type === "header") {
        return (_jsx(SingleSelectListItem, { ref: setMenuItemRef(menuItem.itemId), type: menuItem.type, title: menuItem.itemName, className: menuItem.className, accessibilityConfig: {
                role: "presentation",
            } }, menuItem.itemId));
    }
    if (menuItem.type === "menu") {
        return renderWithOptionalTooltip(menuItem, ({ selectorClassName, tooltipId }) => (_jsx(SingleSelectListItem, { ref: setMenuItemRef(menuItem.itemId), className: cx("gd-menu-item", menuItem.className, `s-${menuItem.itemId}`, {
                [selectorClassName]: menuItem.tooltip,
                "is-disabled": menuItem.disabled,
            }), title: menuItem.itemName, icon: menuItem.icon, isMenu: true, onClick: menuItem.disabled
                ? undefined
                : () => {
                    setAutofocusSubmenu(true);
                    setParentItemId(menuItem.itemId);
                    setSelectedMenuItem(menuItem);
                }, elementType: "button", accessibilityConfig: {
                role: "menuitem",
                ariaHasPopup: "menu",
                ariaExpanded: selectedMenuItem?.itemId === menuItem.itemId,
                ariaDisabled: menuItem.disabled,
                ariaDescribedBy: menuItem.disabled ? tooltipId : undefined,
            } }, menuItem.itemId)));
    }
    return renderWithOptionalTooltip(menuItem, ({ selectorClassName, tooltipId }) => {
        const hasWarning = !!menuItem.warning;
        const item = (_jsx(SingleSelectListItem, { ref: setMenuItemRef(menuItem.itemId), className: cx("gd-menu-item", menuItem.className, `s-${menuItem.itemId}`, {
                [selectorClassName]: menuItem.tooltip,
                "is-disabled": menuItem.disabled,
            }), title: menuItem.itemName, icon: menuItem.icon, info: menuItem.warning ?? undefined, infoRenderer: hasWarning ? (info) => renderMenuItemWarning(info, isWarningFocusTooltipOpen) : undefined, onClick: menuItem.disabled
                ? undefined
                : () => {
                    menuItem.onClick?.();
                    setIsOpen(false);
                    setSelectedMenuItem(null);
                }, elementType: "button", accessibilityConfig: {
                role: "menuitem",
                ariaDisabled: menuItem.disabled,
                ariaHasPopup: menuItem.opensDialog ? "dialog" : undefined,
                // The warning icon is not focusable and is hidden from AT, so describe the whole item by
                // the warning text for screen-reader users (disabled tooltip takes precedence when present).
                ariaDescribedBy: menuItem.disabled
                    ? tooltipId
                    : hasWarning
                        ? warningTooltipId
                        : undefined,
            } }, menuItem.itemId));
        // Keyboard accessibility: the warning icon has its own hover-only tooltip for mouse users, but it is
        // not focusable. Add a second, focus-triggered tooltip anchored to the whole (focusable) menu item so
        // keyboard users see the warning too. Skip it when a disabled tooltip already takes over on focus.
        if (!hasWarning || menuItem.tooltip) {
            return item;
        }
        return (_jsx(UiTooltip, { id: warningTooltipId, triggerBy: ["focus"], arrowPlacement: "left", optimalPlacement: true, content: menuItem.warning, anchor: item, onOpen: () => setIsWarningFocusTooltipOpen(true), onClose: () => setIsWarningFocusTooltipOpen(false) }));
    });
}
function renderMenuItemWarning(info, suppressHover) {
    return (_jsx("span", { className: "gd-list-icon gd-list-icon-right", "data-testid": "menu-item-info-icon", children: _jsx(UiTooltip, { triggerBy: ["hover"], disabled: suppressHover, arrowPlacement: "left", optimalPlacement: true, content: info, anchor: _jsx(UiIcon, { type: "warning", size: 16, color: "warning", accessibilityConfig: { ariaHidden: true } }) }) }));
}
