import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useContext, forwardRef, useEffect, useMemo, useRef, useState, Fragment } from 'react';
import SearchInput from '../SearchInput';
import Flex from '../Flex';
import Link from '../Link';
import Count from '../Badges/Count';
import { useAfterInitialEffect, useConsolidatedRef, useElement, useEscape, useI18n, useUID } from '../../hooks';
import * as arrowMicroDownIcon from '../Icon/icons/arrow-micro-down.icon';
import { registerIcon } from '../Icon/Icon';
import { createStringMatcher, debounce } from '../../utils';
import TabsContext from './TabsContext';
import { StyledErrorIcon, StyledAllTabsButton, StyledTabs, StylesAllTabsButtonWrapper, StyledAllTabsWrapper, StyledSeparator } from './Tabs.styles';
import Tab from './Tab';
registerIcon(arrowMicroDownIcon);
const AllTabsButton = ({ tabs, tabRefs, currentTabId, onTabClick }) => {
    const menuId = useUID();
    const t = useI18n();
    const menuButtonRef = useRef(null);
    const [search, setSearch] = useState('');
    const searchEleRef = useRef(null);
    const [focusControlEl, setFocusControlEl] = useState();
    const searchRegex = createStringMatcher(search);
    const itemsToRender = useMemo(() => {
        return tabs
            .filter(({ name }) => searchRegex.test(name))
            .map(({ id, name, count, disabled, errors }) => {
            const selected = id === currentTabId;
            const item = { id, primary: name, selected, count, disabled };
            if (errors) {
                item.visual = _jsx(StyledErrorIcon, { name: 'warn-solid' });
            }
            return item;
        });
    }, [tabs, search, currentTabId]);
    useEscape(() => {
        if (!search) {
            menuButtonRef.current?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
            menuButtonRef.current?.focus();
        }
    }, searchEleRef);
    return (_jsx(StyledAllTabsButton, { ref: menuButtonRef, text: t('all_tabs'), iconOnly: true, variant: 'simple', icon: 'arrow-micro-down', menu: {
            listId: menuId,
            mode: 'single-select',
            items: itemsToRender,
            focusControlEl,
            accent: search ? searchRegex : undefined,
            onItemClick: (id, event) => {
                onTabClick?.(id, event);
                setSearch('');
                tabRefs.current[tabs.findIndex(tab => tab.id === id)]?.focus();
            },
            header: (_jsx(SearchInput, { ref: searchEleRef, onSearchChange: setSearch, value: search, role: 'searchbox', "aria-controls": menuId }))
        }, popover: {
            onHide: () => {
                setFocusControlEl(undefined);
                setSearch('');
            },
            onShow: () => {
                if (searchEleRef.current) {
                    setFocusControlEl(searchEleRef.current);
                    searchEleRef.current.focus();
                }
            }
        } }));
};
/**
 * The tabs component will take a list of tab data objects and render out a list of tabs in either vertical or horizontal direction.
 * The tabs component handles which tab is active but will give you a callback function that allows you to make changes when a new tab is activated
 */
const Tabs = forwardRef(function Tabs({ tabs = [], type = 'horizontal', currentTabId, onTabClick, ...restProps }, ref) {
    const [wrapper, setWrapper] = useElement();
    const wrapperRef = useConsolidatedRef(ref, setWrapper);
    const { level } = useContext(TabsContext);
    const [hasScrollBar, setHasScrollBar] = useState(false);
    // Used to keep a reference for every tab in order to focus them with key presses
    const tabRefs = useRef([]);
    // Handles arrow keypresses for changing the focus
    const changeTabFocus = (event, index) => {
        if (tabRefs.current?.length) {
            const { key } = event;
            if (key === 'ArrowRight' || key === 'ArrowDown') {
                const nextIndex = index + 1 < tabs.length ? index + 1 : 0;
                const nextTab = tabRefs.current[nextIndex];
                if (!nextTab?.disabled) {
                    nextTab?.focus();
                }
                else {
                    changeTabFocus(event, nextIndex);
                }
            }
            else if (key === 'ArrowLeft' || key === 'ArrowUp') {
                const prevIndex = index === 0 ? tabs.length - 1 : index - 1;
                const prevTab = tabRefs.current[prevIndex];
                if (!prevTab?.disabled) {
                    prevTab?.focus();
                }
                else {
                    changeTabFocus(event, prevIndex);
                }
            }
        }
    };
    useAfterInitialEffect(() => {
        const event = new Event('cosmos-tab-changed', { bubbles: true, composed: true });
        wrapperRef.current?.dispatchEvent(event);
        const currentTabEl = tabRefs.current.find(tab => tab && tab.id === currentTabId);
        currentTabEl?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }, [currentTabId]);
    useEffect(() => {
        if (!wrapper)
            return;
        const ro = new ResizeObserver(debounce(([entry]) => {
            if (!entry?.target.isConnected || !(entry.target instanceof HTMLElement))
                return;
            setHasScrollBar(entry.target.scrollWidth > entry.target.offsetWidth);
        }, 1));
        ro.observe(wrapper);
        return () => {
            ro.disconnect();
        };
    }, [wrapper]);
    const shouldRenderAllTabsButton = type === 'horizontal' && hasScrollBar;
    const TabList = (_jsx(Flex, { ...restProps, container: {
            direction: type !== 'horizontal' ? 'column' : undefined,
            pad: type === 'horizontal' && !hasScrollBar && level === 1 ? [0, 0, 0, 0.5] : undefined
        }, item: { shrink: 0 }, as: StyledTabs, ref: wrapperRef, type: type, role: 'tablist', "aria-orientation": type, hasScrollBar: hasScrollBar, level: level, children: tabs.map((tab, i) => {
            const { href, name, count, id, disabled, errors } = tab;
            const selected = id === currentTabId;
            return (_jsxs(Fragment, { children: [level > 1 && (_jsx(StyledSeparator, { transparent: selected ||
                            (i === 0 ? !shouldRenderAllTabsButton : tabs[i - 1].id === currentTabId) })), _jsx(Tab, { id: id, "aria-selected": selected, "aria-controls": `${id}-panel`, content: name, count: typeof count === 'number' && _jsx(Count, { children: count }), href: href, selected: selected, onClick: (event) => {
                            onTabClick?.(id, event);
                        }, role: 'tab', ref: el => {
                            tabRefs.current[i] = el;
                        }, onKeyDown: (e) => {
                            if (['ArrowRight', 'ArrowDown', 'ArrowLeft', 'ArrowUp'].includes(e.key)) {
                                e.preventDefault();
                                changeTabFocus(e, i);
                            }
                        }, as: href ? Link : undefined, tabIndex: selected ? undefined : -1, "aria-label": name, type: type, disabled: disabled, errors: errors })] }, id));
        }) }));
    return shouldRenderAllTabsButton ? (_jsxs(Flex, { container: { alignItems: 'stretch' }, as: StyledAllTabsWrapper, level: level, children: [_jsx(Flex, { container: true, as: StylesAllTabsButtonWrapper, children: _jsx(AllTabsButton, { tabs: tabs, tabRefs: tabRefs, currentTabId: currentTabId, onTabClick: onTabClick }) }), TabList] })) : (TabList);
});
export default Tabs;
//# sourceMappingURL=Tabs.js.map