import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useRef, useCallback, useMemo, useState, useEffect } from 'react';
import styled from 'styled-components';
import { defaultThemeProp } from '../../../theme';
import Selectable from '../../Badges/Selection';
import { StyledFormControl } from '../../FormControl';
import Flex from '../../Flex';
import { useConsolidatedRef, useActiveDescendant, useDirection, useI18n, useUID } from '../../../hooks';
import { cap, isInstance, getActiveElement } from '../../../utils';
import VisuallyHiddenText from '../../VisuallyHiddenText';
import { StyledSelectInput } from '../ComboBox.styles';
export const StyledMultiSelectInput = styled(StyledSelectInput) `
  cursor: text;

  ul {
    list-style: none;
    display: contents;
  }

  input {
    width: 8ch;
    height: 1.125rem;
  }
`;
StyledMultiSelectInput.defaultProps = defaultThemeProp;
const MultiSelectInput = forwardRef(function MultiSelectInput(props, ref) {
    const { selected = [], value, onRemove, onChange, onKeyDown, onResolveSuggestion, actions, readOnly, disabled, status, placeholder, autoFocus, pauseDescendantEvaluation, onSelectedFocus, onSelectedBlur, 'aria-controls': ariaControls, required, ...restProps } = props;
    const t = useI18n();
    const id = useUID();
    const inputRef = useConsolidatedRef(ref);
    const listRef = useRef(null);
    const [focusDescendant, setFocusDescendant] = useState(null);
    const [activeItemId, setActiveItemId] = useState(null);
    const { start, end } = useDirection();
    const uadConfig = useMemo(() => ({
        focusEl: inputRef.current,
        scope: listRef.current,
        selector: ':scope > li',
        orientation: 'horizontal',
        focusReturnEl: focusDescendant,
        clearFocusReturn: () => {
            setFocusDescendant(null);
        },
        pauseDescendantEvaluation,
        preventInitialScroll: true,
        onClick: (el) => {
            el.click();
        }
    }), [pauseDescendantEvaluation, selected, focusDescendant]);
    const { activeDescendant } = useActiveDescendant(uadConfig, [selected]);
    const handleSelectedRemoval = useCallback((selectionId, idx) => {
        if (!pauseDescendantEvaluation) {
            if (idx === selected.length - 1) {
                // If removing last selected item
                if (selected.length > 1) {
                    // If other selected items, focus previous
                    setFocusDescendant(listRef.current?.querySelectorAll(uadConfig.selector)[idx - 1] ||
                        null);
                }
                else {
                    // Blur selected if final only item removed
                    onSelectedBlur?.();
                }
            }
            else if (selected.length > 1) {
                // If not last item removed and other selected items, focus next
                setFocusDescendant(listRef.current?.querySelectorAll(uadConfig.selector)[idx + 1] ||
                    null);
            }
        }
        onRemove?.(selectionId, idx);
        inputRef.current?.focus();
    }, [selected, onRemove, onSelectedBlur, uadConfig]);
    useEffect(() => {
        // Maintain active item & prev. val only as it changes.
        if (activeDescendant?.id && activeDescendant.id !== activeItemId) {
            setActiveItemId(activeDescendant.id);
        }
    }, [activeDescendant]);
    const onListArrowKeyDown = useCallback((e) => {
        // Tab (forward) from within the list: move focus to the input
        if (e.key === 'Tab' && !e.shiftKey) {
            e.preventDefault();
            inputRef.current?.focus();
            return;
        }
        // Shift+Tab from within the list: exit the combobox entirely
        if (e.key === 'Tab' && e.shiftKey) {
            const focusables = Array.from(listRef.current?.querySelectorAll('a, button') ?? []);
            const elementsToRestore = inputRef.current
                ? [...focusables, inputRef.current]
                : focusables;
            const previousTabIndexes = elementsToRestore.map(el => ({
                el,
                tabindex: el.getAttribute('tabindex')
            }));
            elementsToRestore.forEach(el => el.setAttribute('tabindex', '-1'));
            requestAnimationFrame(() => {
                previousTabIndexes.forEach(({ el, tabindex }) => {
                    if (tabindex === null) {
                        el.removeAttribute('tabindex');
                    }
                    else {
                        el.setAttribute('tabindex', tabindex);
                    }
                });
            });
            return;
        }
        if (e.key !== `Arrow${cap(start)}` && e.key !== `Arrow${cap(end)}`)
            return;
        const items = Array.from(listRef.current?.querySelectorAll(uadConfig.selector) ?? []);
        const currentIndex = items.findIndex(item => item === getActiveElement() || item.contains(getActiveElement()));
        if (currentIndex === -1)
            return;
        e.preventDefault();
        e.stopPropagation();
        if (e.key === `Arrow${cap(start)}` && currentIndex > 0) {
            const prev = items[currentIndex - 1];
            const prevLink = prev.querySelector('a');
            const focusTarget = isInstance(prevLink, HTMLElement) ? prevLink : prev;
            focusTarget.focus();
        }
        else if (e.key === `Arrow${cap(end)}`) {
            if (currentIndex < items.length - 1) {
                const next = items[currentIndex + 1];
                const nextLink = next.querySelector('a');
                const focusTarget = isInstance(nextLink, HTMLElement) ? nextLink : next;
                focusTarget.focus();
            }
            else {
                inputRef.current?.focus();
            }
        }
    }, [start, end, uadConfig.selector]);
    const onInputKeyDown = useCallback((e) => {
        // Shift+Tab: Focus the last selected item's link
        if (e.key === 'Tab' && e.shiftKey && selected.length) {
            const items = Array.from(listRef.current?.querySelectorAll(uadConfig.selector) ?? []);
            const lastItem = items[items.length - 1];
            const link = lastItem?.querySelector('a');
            if (isInstance(link, HTMLElement)) {
                e.preventDefault();
                e.stopPropagation();
                link.focus();
                return;
            }
        }
        if (selected.length &&
            inputRef.current?.selectionStart === 0 &&
            inputRef.current?.selectionEnd === 0) {
            const lastIndex = selected.length - 1;
            if (pauseDescendantEvaluation && e.key === `Arrow${cap(start)}`) {
                setFocusDescendant(listRef.current?.querySelectorAll(uadConfig.selector)[lastIndex] ||
                    null);
                onSelectedFocus?.();
            }
            const lastSelectableId = listRef.current?.querySelectorAll(uadConfig.selector)[lastIndex]
                ?.id;
            const onLastItem = activeItemId === lastSelectableId;
            if (!pauseDescendantEvaluation &&
                ((onLastItem && e.key === `Arrow${cap(end)}`) || e.key === 'ArrowDown')) {
                onSelectedBlur?.();
            }
            if (['Backspace', 'Delete'].includes(e.key) && !(readOnly || disabled)) {
                handleSelectedRemoval(selected[lastIndex].id, lastIndex);
            }
        }
        onKeyDown?.(e);
    }, [
        pauseDescendantEvaluation,
        activeItemId,
        onKeyDown,
        handleSelectedRemoval,
        selected,
        readOnly,
        disabled,
        start,
        uadConfig.selector,
        onSelectedFocus,
        onSelectedBlur
    ]);
    const ariaDescribedBy = useMemo(() => {
        return onChange
            ? `${id}-inputDescription  ${id}-searchDescription`
            : `${id}-inputDescription`;
    }, [id]);
    const ariaControlsValue = useMemo(() => {
        if (!pauseDescendantEvaluation) {
            return selected.length > 0 ? id : undefined;
        }
        return ariaControls;
    }, [pauseDescendantEvaluation, selected.length]);
    return (_jsxs(Flex, { as: StyledMultiSelectInput, forwardedAs: StyledFormControl, hasSuggestion: status === 'pending' && !!onResolveSuggestion, container: { alignItems: 'center', justify: 'between' }, readOnly: readOnly, disabled: disabled, status: status, children: [_jsxs(Flex, { container: { alignContent: 'center', wrap: 'wrap', rowGap: 0.5, colGap: 0.25, pad: 0.25 }, item: { grow: 1 }, onClick: (e) => {
                    // Ignore clicks on selection items
                    if (isInstance(e.target, HTMLElement) &&
                        !isInstance(e.target, HTMLInputElement) &&
                        !e.currentTarget.contains(e.target.closest('li'))) {
                        e.stopPropagation();
                        inputRef.current?.focus();
                        inputRef.current?.click();
                    }
                }, children: [selected.length > 0 && (
                    // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
                    _jsx("ul", { ref: listRef, id: id, "aria-label": t('selected_items'), onKeyDown: onListArrowKeyDown, children: selected.map((element, idx) => {
                            return (_jsx(Selectable, { as: 'li', id: element.id.toString(), status: status, contextualLabel: element.text, onRemove: !readOnly && !disabled
                                    ? () => {
                                        handleSelectedRemoval(element.id, idx);
                                    }
                                    : undefined, tabIndex: -1, "aria-label": `${t('remove')} ${element.text}`, "aria-describedby": ariaDescribedBy, children: element.primary ?? element.text }, element.id));
                        }) })), _jsx(Flex, { item: { grow: 1 }, as: 'input', size: 1, ref: inputRef, value: value, 
                        // no-op avoids react uncontrolled warning
                        onChange: onChange || (() => { }), onKeyDown: onInputKeyDown, readOnly: readOnly || !onChange, disabled: disabled, placeholder: selected?.length ? undefined : placeholder, autoComplete: '_off', autoFocus: autoFocus, "aria-controls": ariaControlsValue, "aria-required": !!required, ...restProps })] }), actions, _jsx(VisuallyHiddenText, { id: `${id}-inputDescription`, children: `${t('combobox_open_close')} ` }), _jsx(VisuallyHiddenText, { id: `${id}-searchDescription`, children: t('combobox_search_instructions') })] }));
});
export default MultiSelectInput;
//# sourceMappingURL=MultiSelectInput.js.map