import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useState, useCallback, useEffect, useRef } from 'react';
import Icon, { registerIcon } from '../Icon';
import * as searchIcon from '../Icon/icons/search.icon';
import * as timesIcon from '../Icon/icons/times.icon';
import { useConsolidatedRef, useEscape, useI18n, useOuterEvent, useLiveLog, useUID, useFocusWithin, useTheme } from '../../hooks';
import Flex from '../Flex';
import Popover from '../Popover';
import { sameWidth } from '../Popover/modifiers';
import Menu from '../Menu';
import Link from '../Link';
import Text from '../Text';
import { createStringMatcher, getFocusables, createClassName } from '../../utils';
import VisuallyHiddenText from '../VisuallyHiddenText';
import Tooltip from '../Tooltip';
import { ThemeOverride } from '../Configuration';
import { StyledClearButton, StyledResultsPopover, StyledSearchButton, StyledSearchInput, StyledSearchMenu, StyledSearchResultsContainer, StyledSearchTextInput, StyledSearchFiltersButton, StyledSearchIcon } from './SearchInput.styles';
registerIcon(searchIcon, timesIcon);
const SearchInput = forwardRef(function SearchInput(props, ref) {
    const t = useI18n();
    const { value = '', defaultFilter, currentFilter, filters, onFilterChange, searchResults, recentSearches, loading: loadingProp, advancedSearchLink, onSearchChange, onSearchSubmit, onKeyDown: onKeyDownProp, searchInputAriaLabel = t('search'), resultsPopover = true, className, ...restProps } = props;
    const id = useUID();
    const listId = useUID();
    const instructionTextId = useUID();
    const { announcePolite } = useLiveLog();
    const bodyRef = useRef(document.body);
    const inputRef = useConsolidatedRef(ref);
    const filtersRef = useRef(null);
    const searchResultsRef = useRef(null);
    const theme = useTheme();
    const [searchMenuOpen, setSearchMenuOpen] = useState(false);
    const [searchResultItems, setSearchResultItems] = useState(undefined);
    const [downPressed, setDownPressed] = useState(false);
    const [selectedFilter, setSelectedFilter] = useState(currentFilter ?? defaultFilter ?? t('all'));
    const completeFilters = [t('all'), ...(filters ?? [])];
    const hasFilters = completeFilters.length > 1;
    const hasSearchResults = !!(searchResults && searchResults.length);
    const hasRecentSearches = !!(recentSearches && recentSearches.length);
    const showSearchMenu = (value || recentSearches?.length) && (searchResultItems || loadingProp);
    const useRecents = hasRecentSearches && !value;
    const loading = useRecents ? false : !!loadingProp;
    const searchMenuVisible = (resultsPopover && showSearchMenu && searchMenuOpen) || (!resultsPopover && showSearchMenu);
    const handleEscape = useCallback((e) => {
        if (searchMenuOpen) {
            e.preventDefault();
            e.stopPropagation();
            setSearchMenuOpen(false);
            setDownPressed(false);
        }
    }, [searchMenuOpen]);
    useEscape(handleEscape, inputRef, [handleEscape]);
    const onKeyDown = useCallback((e) => {
        onKeyDownProp?.(e);
        switch (e.key) {
            case 'Enter':
                if (!downPressed) {
                    onSearchSubmit?.(value);
                }
                break;
            case 'ArrowDown':
                setDownPressed(true);
                setSearchMenuOpen(true);
                break;
            case 'Tab': {
                const forward = !e.shiftKey;
                if (forward) {
                    const popoverFocusables = getFocusables(searchResultsRef);
                    if (popoverFocusables.length) {
                        e.preventDefault();
                        popoverFocusables[0].focus();
                    }
                }
                break;
            }
            default:
                break;
        }
    }, [onSearchSubmit, downPressed, value]);
    useOuterEvent('click', [searchResultsRef, inputRef, filtersRef], () => {
        setSearchMenuOpen(false);
    });
    useEffect(() => {
        setDownPressed(false);
    }, [value]);
    useEffect(() => {
        let items = [];
        if (hasSearchResults && value) {
            items = searchResults;
        }
        else if (useRecents) {
            items = recentSearches;
        }
        else if (!searchResults && (!recentSearches || recentSearches.length === 0)) {
            items = undefined;
        }
        setSearchResultItems(items);
    }, [searchResults, recentSearches, searchMenuOpen, hasSearchResults, hasRecentSearches, value]);
    // Announce results
    useEffect(() => {
        if (!searchMenuVisible || loading)
            return;
        const timeout = setTimeout(() => {
            announcePolite({
                message: t(useRecents ? 'recent_results_count' : 'results_count', [searchResultItems?.length ?? 0], {
                    count: searchResultItems?.length ?? 0
                }),
                type: 'status'
            });
        }, 1000);
        return () => {
            clearTimeout(timeout);
        };
    }, [loading, searchMenuVisible, searchResultItems]);
    const searchMenu = (_jsx(Menu, { as: StyledSearchMenu, listId: listId, role: 'listbox', header: recentSearches && !value ? (_jsx(Text, { variant: 'secondary', children: t('recent_searches') })) : undefined, mode: 'action', items: searchResultItems ?? [], loading: loading, footer: advancedSearchLink ? (_jsx(Link, { ...advancedSearchLink, children: t('advanced_search') })) : undefined, accent: hasSearchResults ? createStringMatcher(value, undefined, 'gi') : undefined, focusControlEl: inputRef.current || undefined, pauseDescendantEvaluation: !downPressed, "aria-label": searchInputAriaLabel || t('search') }));
    const focus = useFocusWithin([inputRef, searchResultsRef], focused => {
        if (!focused) {
            setDownPressed(false);
            setSearchMenuOpen(false);
        }
    });
    useEffect(() => {
        if (focus) {
            setSearchMenuOpen(true);
        }
    }, [focus]);
    useEffect(() => {
        if (currentFilter !== undefined) {
            setSelectedFilter(currentFilter);
        }
    }, [currentFilter]);
    return (_jsxs(_Fragment, { children: [_jsxs(Flex, { container: true, as: StyledSearchInput, hasFilters: hasFilters, showSubmit: !!onSearchSubmit, className: createClassName('search-input', className, { loading: !!loadingProp }), children: [hasFilters && (_jsxs(_Fragment, { children: [_jsx(ThemeOverride, { theme: {
                                    components: {
                                        button: {
                                            'secondary-color': theme.base.palette['foreground-color'],
                                            'secondary-fill-style': 'outline'
                                        }
                                    }
                                }, children: _jsx(StyledSearchFiltersButton, { ref: filtersRef, text: selectedFilter, variant: 'secondary', "aria-label": t('search_in_noun', [selectedFilter]), menu: {
                                        mode: 'single-select',
                                        items: completeFilters.map(filter => ({
                                            primary: filter,
                                            id: filter,
                                            selected: selectedFilter === filter,
                                            onClick: () => {
                                                setSelectedFilter(filter);
                                                onFilterChange?.(filter);
                                                inputRef.current?.focus();
                                            }
                                        }))
                                    }, showSubmit: !!onSearchSubmit }) }), _jsx(Tooltip, { target: filtersRef.current, hideDelay: 'none', showDelay: 'none', children: t('search_in') })] })), !onSearchSubmit && !hasFilters && _jsx(StyledSearchIcon, { name: 'search' }), _jsx(StyledSearchTextInput, { id: id, ref: inputRef, "aria-label": searchInputAriaLabel, ...restProps, type: 'search', "aria-autocomplete": 'list', "aria-controls": !!showSearchMenu && resultsPopover ? listId : undefined, "aria-haspopup": 'listbox', "aria-describedby": searchMenuVisible ? instructionTextId : undefined, value: value, onChange: (e) => {
                            onSearchChange?.(e.target.value);
                            if (e.target.value)
                                setSearchMenuOpen(true);
                        }, onKeyDown: onKeyDown, autoComplete: 'off' }), value && (_jsx(StyledClearButton, { icon: true, onClick: () => {
                            onSearchChange?.('');
                            inputRef.current?.focus();
                        }, variant: 'simple', compact: true, label: t('clear'), showSubmit: !!onSearchSubmit, children: _jsx(Icon, { name: 'times' }) })), !onSearchSubmit && hasFilters && _jsx(StyledSearchIcon, { name: 'search' }), onSearchSubmit && (_jsx(StyledSearchButton, { onClick: () => {
                            onSearchSubmit?.(value);
                        }, icon: true, label: t('search'), variant: 'simple', children: _jsx(Icon, { name: 'search' }) }))] }), showSearchMenu && resultsPopover && (_jsx(Popover, { as: StyledResultsPopover, target: inputRef.current, show: searchMenuOpen, placement: 'bottom-start', modifiers: [sameWidth], onKeyDown: (e) => {
                    if (!inputRef.current)
                        return;
                    if (e.key === 'Tab') {
                        const popoverFocusables = getFocusables(searchResultsRef);
                        const currentIndex = popoverFocusables.indexOf(e.target);
                        const forward = !e.shiftKey;
                        const isLast = currentIndex === popoverFocusables.length - 1;
                        if (forward && isLast) {
                            e.preventDefault();
                            const allFocusable = getFocusables(bodyRef);
                            const nextIndex = allFocusable.indexOf(inputRef.current) + 1;
                            allFocusable[nextIndex]?.focus();
                            setDownPressed(false);
                            setSearchMenuOpen(false);
                        }
                        else if (!forward && currentIndex === 0) {
                            e.preventDefault();
                            inputRef.current.focus();
                        }
                    }
                    if (e.key === 'Escape') {
                        handleEscape(e);
                        inputRef.current.focus();
                    }
                }, ref: searchResultsRef, children: searchMenu })), !resultsPopover && showSearchMenu && (_jsx(StyledSearchResultsContainer, { children: searchMenu })), _jsx(VisuallyHiddenText, { id: instructionTextId, children: `${t('search_instructions')} ` })] }));
});
export default SearchInput;
//# sourceMappingURL=SearchInput.js.map