import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { createElement as _createElement } from "react";
import { forwardRef, useContext, useEffect, useLayoutEffect, useRef, useState, useMemo, Fragment, useCallback } from 'react';
import Drawer from '../Drawer';
import { useAfterInitialEffect, useConsolidatedRef, useItemIntersection, useI18n, useDirection, useLiveLog } from '../../hooks';
import Progress from '../Progress';
import EmptyState from '../EmptyState';
import MenuContext from './Menu.context';
import MenuListHeader from './MenuListHeader';
import MenuItem from './MenuItem';
import helpers from './helpers';
import { StyledLoadingItem, StyledMenuList, StyledMenuListContainer, StyledSeparator } from './Menu.styles';
import { resizeRootEl } from './NavItemsList';
import MenuGroup from './MenuGroup';
import { isParentMenuItem } from './Menu.utils';
const setParentDisabled = (fieldset, bool) => {
    fieldset.disabled = bool;
    const legendButton = fieldset.querySelector('legend button');
    if (legendButton) {
        legendButton.disabled = bool;
    }
};
const countVisibleItems = (menuItems, loading) => {
    return menuItems.reduce((acc, item) => {
        const isFlatGroup = !helpers.isItem(item);
        if (isFlatGroup && item.items) {
            return acc + item.items.length + 1;
        }
        return acc + 1;
    }, loading ? 1 : 0);
};
const flattenedGroupItems = (items) => {
    return items.flatMap(item => {
        if (helpers.isItem(item))
            return item;
        return [item, ...(item.items ? item.items : [])];
    });
};
const MenuList = forwardRef(function MenuListFunction({ items, parent, id, menuRole, ...restProps }, ref) {
    const t = useI18n();
    const menuListWrapperRef = useRef(null);
    const selfRef = useConsolidatedRef(ref);
    const ulRef = useRef(null);
    const returnFocusRef = useRef(null);
    const [open, setOpen] = useState(!parent);
    const [expandedItem, setExpandedItem] = useState();
    const { scrollAt, 'aria-label': label, loadMore, loading, emptyText, currentItemId, onItemExpand, focusControl, updateActiveDescendants, setFocusReturnEl, onItemCollapse, expandTo } = useContext(MenuContext);
    const { end } = useDirection();
    const { announcePolite } = useLiveLog();
    useItemIntersection(ulRef, items.length - 1, () => {
        if (!loading)
            loadMore?.(parent?.item?.id);
    }, ':scope > li');
    useLayoutEffect(() => {
        if (!selfRef.current || expandedItem)
            return;
        menuListWrapperRef.current = selfRef.current.parentElement;
        resizeRootEl(selfRef.current, menuListWrapperRef.current, countVisibleItems(items, loading), scrollAt);
    });
    useEffect(() => {
        if (parent)
            setOpen(true);
    }, []);
    useAfterInitialEffect(() => {
        if (expandedItem) {
            const foundItem = flattenedGroupItems(items).find(item => item.id === expandedItem.id);
            if (foundItem && isParentMenuItem(foundItem)) {
                setExpandedItem(foundItem);
            }
            else {
                setExpandedItem(undefined);
            }
        }
    }, [expandedItem, items]);
    useAfterInitialEffect(() => {
        if (currentItemId) {
            // if there is ancestor item of the controlled item, set it to expanded.
            const ancestor = flattenedGroupItems(items).find(item => item.items?.length && helpers.getItem(item.items, currentItemId) !== undefined);
            if (ancestor) {
                setExpandedItem(isParentMenuItem(ancestor) ? ancestor : undefined);
                updateActiveDescendants({ preventScroll: true });
            }
        }
    }, [currentItemId, items, parent]);
    useEffect(() => {
        if (expandTo?.parentItemId) {
            const expandToChild = flattenedGroupItems(items).find(item => item.id === expandTo.parentItemId);
            if (expandToChild) {
                setExpandedItem(isParentMenuItem(expandToChild) ? expandToChild : undefined);
                updateActiveDescendants({ preventScroll: true });
                expandTo.onComplete();
            }
            else {
                const next = flattenedGroupItems(items).find(item => item.items?.length &&
                    helpers.getItem(item.items, expandTo.parentItemId) !== undefined);
                if (next) {
                    setExpandedItem(isParentMenuItem(next) ? next : undefined);
                }
                else {
                    // Abort if target is not available in items
                    expandTo.onComplete();
                }
            }
        }
    }, [expandTo, items, parent]);
    const onExpandCallback = useCallback((itemId, e) => {
        const item = helpers.getItem(items, itemId);
        returnFocusRef.current = e.currentTarget;
        if (item && isParentMenuItem(item)) {
            setExpandedItem(item);
        }
        else {
            setExpandedItem(undefined);
        }
        item?.onExpand?.(itemId, e);
        onItemExpand?.(itemId, e);
        updateActiveDescendants({ preventScroll: true });
    }, [items]);
    useEffect(() => {
        if (items.length === 0 && !loading) {
            announcePolite({ message: emptyText ?? t('no_items') });
        }
    }, [items.length, loading]);
    const listContent = useMemo(() => {
        if (items.length) {
            return items.map((item, index) => {
                return helpers.isItem(item) ? (_createElement(MenuItem, { ...item, key: item.id, role: menuRole === 'listbox' ? 'option' : 'menuitem', onExpand: item.items ? onExpandCallback : undefined })) : (_jsxs(Fragment, { children: [_jsx(MenuGroup, { ...item, items: item.items.map(i => (i.items ? { ...i, onExpand: onExpandCallback } : i)), itemRole: menuRole === 'listbox' ? 'option' : 'menuitem' }), items[index + 1] && helpers.isItem(items[index + 1]) && (_jsx(StyledSeparator, { role: 'separator' }))] }, item.id));
            });
        }
        if (!loading) {
            return _jsx(EmptyState, { message: emptyText, forwardedAs: 'li' });
        }
        return null;
    }, [items, loading, emptyText]);
    const list = (_jsxs(StyledMenuList, { id: expandedItem ? undefined : id, ref: ulRef, role: menuRole, ...restProps, children: [parent && (_jsx(MenuListHeader, { text: parent.item.primary, onClick: () => {
                    setOpen(false);
                } })), listContent, loading && !expandedItem && (_jsx(StyledLoadingItem, { children: _jsx(Progress, { placement: 'local', liveConfig: { contextualLabel: label ?? t('menu') } }) }))] }));
    return (_jsxs(_Fragment, { children: [_jsx(Drawer, { "aria-hidden": !!expandedItem, as: StyledMenuListContainer, ref: selfRef, open: open, style: { opacity: expandedItem ? 0 : 1 }, disabled: !!expandedItem, placement: end, onBeforeOpen: () => {
                    if (parent) {
                        parent.el.style.opacity = '0';
                    }
                    if (selfRef.current) {
                        selfRef.current.style.opacity = '1';
                    }
                }, onAfterOpen: () => {
                    if (parent) {
                        setParentDisabled(parent.el, true);
                    }
                }, onBeforeClose: () => {
                    if (parent && menuListWrapperRef.current) {
                        setParentDisabled(parent.el, false);
                        parent.el.style.opacity = '1';
                        resizeRootEl(parent.el, menuListWrapperRef.current, countVisibleItems(parent.siblingItems), scrollAt);
                    }
                    if (selfRef.current) {
                        selfRef.current.style.opacity = '0';
                    }
                }, onAfterClose: () => {
                    if (parent) {
                        focusControl?.focus();
                        const expandBtn = parent.returnFocusRef.current;
                        parent.setExpandedItem(undefined);
                        if (expandBtn) {
                            setFocusReturnEl(expandBtn?.closest('li'));
                        }
                        onItemCollapse?.(parent.item.id);
                        updateActiveDescendants();
                    }
                }, children: list }), expandedItem && selfRef.current && (_jsx(MenuList, { id: id, items: expandedItem.items, parent: {
                    el: selfRef.current,
                    item: expandedItem,
                    siblingItems: items,
                    setExpandedItem,
                    returnFocusRef
                }, menuRole: menuRole }))] }));
});
export default MenuList;
//# sourceMappingURL=MenuList.js.map