'use strict';

var React = require('react');
var ComboboxContent = require('./ComboboxContent-cjs.js');
var ComboboxAction = require('./ComboboxAction-cjs.js');
var ComboboxProvider = require('./ComboboxProvider-cjs.js');
var ComboboxTrigger = require('./ComboboxTrigger-cjs.js');
var ComboboxOption = require('./ComboboxOption-cjs.js');
var noop = require('./noop-cjs.js');
var jobberHooks = require('@jobber/hooks');
var ComboboxActivator = require('./ComboboxActivator-cjs.js');

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

function useMakeComboboxHandlers(setOpen, open, setSearchValue, selectedOptions, shouldScroll, selectedStateSetter, multiSelect, onClose, onSearch) {
    const handleClose = React.useCallback(() => {
        setOpen(false);
        setSearchValue("");
        onSearch && onSearch("");
        onClose && onClose();
        if (selectedOptions.length > 0) {
            shouldScroll.current = true;
        }
    }, [setOpen, setSearchValue, onClose, onSearch, selectedOptions.length]);
    const handleOpen = React.useCallback(() => {
        setOpen(true);
    }, [setOpen]);
    const handleSelection = React.useCallback((selection) => {
        if (multiSelect) {
            handleMultiSelect(selectedStateSetter, selectedOptions, selection);
        }
        else {
            handleSingleSelect(selectedStateSetter, selection);
        }
    }, [multiSelect, selectedStateSetter, selectedOptions]);
    const handleSingleSelect = React.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 = React.useRef(null);
    const shouldScroll = React.useRef(false);
    const [open, setOpen] = React.useState(false);
    const [searchValue, setSearchValue] = React.useState("");
    const searchCallback = jobberHooks.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.noop,
    };
}

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

function Combobox(props) {
    const { optionElements, triggerElement, actionElements } = useComboboxValidation(props.children);
    const options = React.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.createElement(ComboboxProvider.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.createElement("div", { ref: wrapperRef, className: styles.wrapper },
            open && (React.createElement("div", { className: styles.overlay, onClick: handleClose, "data-testid": "ATL-Combobox-Overlay" })),
            triggerElement || (React.createElement(ComboboxTrigger.ComboboxTrigger, { label: props.label, selected: props.selected, activatorRef: props.defaultActivatorRef })),
            React.createElement(ComboboxContent.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.ComboboxActivator;
Combobox.Action = ComboboxAction.ComboboxAction;
Combobox.Option = ComboboxOption.ComboboxOption;

exports.Combobox = Combobox;
