import React__default, { useCallback, useRef, useState, Children, isValidElement, useMemo } from 'react';
import { C as ComboboxContent } from './ComboboxContent-es.js';
import { C as ComboboxAction } from './ComboboxAction-es.js';
import { C as ComboboxContextProvider } from './ComboboxProvider-es.js';
import { C as ComboboxTrigger } from './ComboboxTrigger-es.js';
import { C as ComboboxOption } from './ComboboxOption-es.js';
import { n as noop } from './noop-es.js';
import { useDebounce } from '@jobber/hooks';
import { C as ComboboxActivator } from './ComboboxActivator-es.js';

var styles = {"overlay":"xxU2WqkpXZU-","wrapper":"W-9SMjhEMpI-","spinning":"mqMvu8yxz2w-"};

function useMakeComboboxHandlers(setOpen, open, setSearchValue, selectedOptions, shouldScroll, selectedStateSetter, multiSelect, onClose, onSearch) {
    const handleClose = useCallback(() => {
        setOpen(false);
        setSearchValue("");
        onSearch && onSearch("");
        onClose && onClose();
        if (selectedOptions.length > 0) {
            shouldScroll.current = true;
        }
    }, [setOpen, setSearchValue, onClose, onSearch, selectedOptions.length]);
    const handleOpen = useCallback(() => {
        setOpen(true);
    }, [setOpen]);
    const handleSelection = useCallback((selection) => {
        if (multiSelect) {
            handleMultiSelect(selectedStateSetter, selectedOptions, selection);
        }
        else {
            handleSingleSelect(selectedStateSetter, selection);
        }
    }, [multiSelect, selectedStateSetter, selectedOptions]);
    const handleSingleSelect = useCallback((selectCallback, selection) => {
        selectCallback([selection]);
        handleClose();
    }, []);
    return {
        handleClose,
        handleSelection,
        handleOpen,
    };
}
function handleMultiSelect(selectCallback, selected, selection) {
    if (selected.some(s => s.id === selection.id)) {
        selectCallback(selected.filter(s => s.id !== selection.id));
    }
    else {
        selectCallback([...selected, selection]);
    }
}

function useCombobox(selected, onSelect, options, onClose, multiSelect, onSearch, debounceTime = 300) {
    const wrapperRef = useRef(null);
    const shouldScroll = useRef(false);
    const [open, setOpen] = useState(false);
    const [searchValue, setSearchValue] = useState("");
    const searchCallback = useDebounce((value) => onSearch === null || onSearch === void 0 ? void 0 : onSearch(value), debounceTime);
    const { handleClose, handleSelection, handleOpen } = useMakeComboboxHandlers(setOpen, open, setSearchValue, selected, shouldScroll, onSelect, multiSelect, onClose, onSearch);
    const internalFilteredOptions = options.filter(option => option.label.toLowerCase().includes(searchValue.toLowerCase()));
    return {
        wrapperRef,
        searchValue,
        setSearchValue,
        open,
        selectedOptions: selected,
        selectedStateSetter: onSelect,
        shouldScroll,
        handleClose,
        handleSelection,
        handleOpen,
        internalFilteredOptions,
        handleSearchChange: onSearch ? searchCallback : noop,
    };
}

function useComboboxValidation(children) {
    const optionElements = getCompoundComponents(ComboboxOption, children);
    const actionElements = getCompoundComponents(ComboboxAction, children);
    const activatorElements = getCompoundComponents(ComboboxActivator, children);
    return {
        optionElements,
        triggerElement: activatorElements[0],
        actionElements,
    };
}
/**
 * Return all instances child component that matches the `type` provided
 */
function getCompoundComponents(type, children) {
    const childrenArray = Children.toArray(children);
    const elements = childrenArray.filter((child) => isValidElement(child) && child.type === type);
    return elements;
}

function Combobox(props) {
    const { optionElements, triggerElement, actionElements } = useComboboxValidation(props.children);
    const options = useMemo(() => (optionElements === null || optionElements === void 0 ? void 0 : optionElements.map(option => (Object.assign({}, option.props)))) || [], [optionElements]);
    const { selectedOptions, selectedStateSetter, shouldScroll, wrapperRef, searchValue, setSearchValue, open, handleClose, handleSelection, handleOpen, internalFilteredOptions, handleSearchChange, } = useCombobox(props.selected, props.onSelect, options, props.onClose, props.multiSelect, props.onSearch, props.onSearchDebounce);
    return (React__default.createElement(ComboboxContextProvider, { selected: selectedOptions, selectionHandler: handleSelection, open: open, handleOpen: handleOpen, handleClose: handleClose, shouldScroll: shouldScroll, searchValue: searchValue, label: props.label, onClear: props.onClear, onSelectAll: props.onSelectAll },
        React__default.createElement("div", { ref: wrapperRef, className: styles.wrapper },
            open && (React__default.createElement("div", { className: styles.overlay, onClick: handleClose, "data-testid": "ATL-Combobox-Overlay" })),
            triggerElement || (React__default.createElement(ComboboxTrigger, { label: props.label, selected: props.selected, activatorRef: props.defaultActivatorRef })),
            React__default.createElement(ComboboxContent, { multiselect: props.multiSelect, subjectNoun: props.subjectNoun, selected: selectedOptions, actionElements: actionElements, selectedStateSetter: selectedStateSetter, handleSelection: handleSelection, searchValue: searchValue, setSearchValue: setSearchValue, wrapperRef: wrapperRef, open: open, options: props.onSearch ? options : internalFilteredOptions, loading: props.loading, handleSearchChange: handleSearchChange, onLoadMore: props.onLoadMore }))));
}
Combobox.Activator = ComboboxActivator;
Combobox.Action = ComboboxAction;
Combobox.Option = ComboboxOption;

export { Combobox as C };
