import { __rest } from '../../../_virtual/_tslib.js';
import React__default, { useRef, useState, useEffect } from 'react';
import { usePopper } from 'react-popper';
import { useOnClickOutside } from '../../../hooks/useClickOutside.js';
import { useDebounce } from '../../../hooks/useDebounce.js';
import { useKeyPress } from '../../../hooks/useKeyPress.js';
import AlertCircle from '../../../icons/AlertCircle.js';
import CloseCircle from '../../../icons/CloseCircle.js';
import ChevronDown from '../../../icons/ChevronDown.js';
import ChevronUp from '../../../icons/ChevronUp.js';
import { getId } from '../../../utils/index.js';
import { OptionsPopper } from '../dropdown/styles.js';
import { Wrapper, LabelWrapper, Label, Text, Border, SupportingText, ErrorMessage, AssistMessage } from '../styles.js';
import { SearchOptions } from './components/SearchOptions.js';
import { InputWrapper, CloseWrapper, IconWrapper } from './styles.js';
import { popperOptions } from './utils.js';
import { MultiValueList } from './components/MultiValueList.js';
import { SearchInput } from './components/SearchInput.js';

function SearchableDropdown(_a) {
    var _b;
    var { variant, id, className, name, label, required, optionalText, errorText, assistText, placeholder, width, hasError = false, options, debounceDelay = 500, noResultsText, onOpen, onClose, onFocus, onBlur, onTextChange, disabled = false, maxHeight = 300, touched } = _a, props = __rest(_a, ["variant", "id", "className", "name", "label", "required", "optionalText", "errorText", "assistText", "placeholder", "width", "hasError", "options", "debounceDelay", "noResultsText", "onOpen", "onClose", "onFocus", "onBlur", "onTextChange", "disabled", "maxHeight", "touched"]);
    const { value, multivalue, onChange } = props;
    const inputRef = useRef(null);
    const [referenceElement, setReferenceElement] = useState(null);
    const [popperElement, setPopperElement] = useState(null);
    const [popperWidth, setPopperWidth] = useState(0);
    const [visible, setVisibility] = useState(false);
    const { containerRef } = useOnClickOutside(() => setVisibility(false));
    const [focusElement, setFocusElement] = useState(-1);
    const [searchValue, setSearchValue] = useState('');
    const [filteredOptions, setFilteredOptions] = useState(options);
    const debouncedValue = useDebounce(searchValue, debounceDelay);
    const arrowDownPressed = useKeyPress('ArrowDown', inputRef);
    const arrowUpPressed = useKeyPress('ArrowUp', inputRef);
    const enterPressed = useKeyPress('Enter', inputRef);
    const [showError, setShowError] = useState(false);
    useEffect(() => {
        const composeError = typeof touched === 'undefined' ? hasError : hasError && touched;
        setShowError(composeError);
    }, [hasError, touched]);
    const { styles, attributes } = usePopper(referenceElement, popperElement, popperOptions);
    const openPopper = () => {
        if (disabled)
            return;
        setVisibility(true);
        onOpen && onOpen();
    };
    const closePopper = () => {
        if (disabled)
            return;
        setVisibility(false);
        onClose && onClose();
    };
    const handleOptionChange = (opt) => {
        if (opt.label && !opt.isDisabled && filteredOptions.length > 0) {
            if (multivalue) {
                onChange(toggleMultivalueItem(opt));
            }
            else {
                setSearchValue(opt.label);
                onChange(opt);
                closePopper();
                setFocusElement(-1);
            }
        }
    };
    const clearSelection = () => {
        if (!multivalue) {
            props.onChange(null);
        }
    };
    const handleInputChange = (event) => {
        if (!visible)
            openPopper();
        const inputValue = event.target.value;
        if (inputValue === '' && !multivalue) {
            setFilteredOptions(options);
            clearSelection();
        }
        setSearchValue(inputValue);
        onTextChange && onTextChange(inputValue);
    };
    const handleInputFocus = () => {
        if (!visible && searchValue === '')
            openPopper();
        onFocus && onFocus();
    };
    const handleSingleClear = (event) => {
        if (!disabled && !multivalue) {
            event.preventDefault();
            event.stopPropagation();
            setFilteredOptions(options);
            setSearchValue('');
            clearSelection();
            closePopper();
        }
    };
    const onRemove = (item) => {
        if (!disabled && multivalue) {
            handleOptionChange(value.find((v) => String(v.value) === String(item)));
        }
    };
    const handleBlur = () => {
        if (searchValue !== '' && filteredOptions.length >= 1 && !value) {
            setSearchValue(filteredOptions[0].label);
        }
        else if (!value || multivalue) {
            setSearchValue('');
        }
        onBlur && onBlur();
    };
    const showClearIcon = () => {
        return !multivalue && value !== null;
    };
    const toggleMultivalueItem = (item) => {
        if (!multivalue) {
            return [];
        }
        return value.some((v) => v.value === item.value)
            ? value.filter((v) => v.value !== item.value)
            : [...value, item];
    };
    useEffect(() => {
        !multivalue && value && setSearchValue(value.label);
    }, [value]);
    useEffect(() => {
        if (containerRef && containerRef.current) {
            setPopperWidth(containerRef.current.clientWidth);
        }
    }, [(_b = containerRef.current) === null || _b === void 0 ? void 0 : _b.clientWidth]);
    useEffect(() => {
        if (debouncedValue && debouncedValue !== '') {
            const filtered = options.filter((opt) => {
                if (debouncedValue.length > 1)
                    return opt.label.toLowerCase().includes(debouncedValue.toLowerCase());
                return opt.label.toLowerCase().startsWith(debouncedValue.toLowerCase());
            });
            setFilteredOptions(filtered);
            setFocusElement(0);
        }
        else {
            setFilteredOptions(options);
        }
    }, [debouncedValue, options]);
    useEffect(() => {
        if (filteredOptions.length > 0) {
            if (arrowDownPressed) {
                if (focusElement < filteredOptions.length - 1) {
                    setFocusElement(focusElement + 1);
                }
            }
            if (arrowUpPressed) {
                if (focusElement >= 1) {
                    setFocusElement(focusElement - 1);
                }
            }
            if (enterPressed && focusElement >= 0) {
                const opt = filteredOptions[focusElement];
                handleOptionChange(opt);
            }
        }
    }, [arrowDownPressed, arrowUpPressed, enterPressed]);
    const appendTestId = getId(props['data-testid']);
    return (React__default.createElement(Wrapper, { className: className, "data-testid": appendTestId('searchable-dropdown'), "data-trackid": props['data-trackid'], "aria-label": props['aria-label'] || label, ref: containerRef, onClick: () => { var _a; return inputRef && ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus()); }, width: width },
        React__default.createElement(LabelWrapper, { disabled: disabled, hasLabel: Boolean(label === null || label === void 0 ? void 0 : label.length) },
            label && (React__default.createElement(Label, { htmlFor: id || `input-${name}`, disabled: disabled }, label)),
            !required && React__default.createElement(Text, null, optionalText)),
        React__default.createElement(Border, { disabled: disabled, hasError: showError, "aria-haspopup": "true", "aria-expanded": visible, ref: setReferenceElement },
            React__default.createElement(InputWrapper, null, multivalue ? (React__default.createElement(MultiValueList, { values: value, onRemove: onRemove, isDisabled: disabled, SearchInputComponent: React__default.createElement(SearchInput, { id: id || `input-${name}`, inputRef: inputRef, testId: appendTestId(), variant: variant, disabled: disabled, placeholder: placeholder, "aria-haspopup": "true", searchValue: searchValue, onChange: handleInputChange, onBlur: handleBlur, onFocus: handleInputFocus }) })) : (React__default.createElement(SearchInput, { id: id || `input-${name}`, inputRef: inputRef, testId: appendTestId(), variant: variant, disabled: disabled, placeholder: placeholder, "aria-haspopup": "true", searchValue: searchValue, onChange: handleInputChange, onBlur: handleBlur, onFocus: handleInputFocus }))),
            showClearIcon() ? (React__default.createElement(CloseWrapper, { disabled: disabled, onMouseDown: handleSingleClear },
                React__default.createElement(CloseCircle, { width: 24, height: 24 }))) : (React__default.createElement(IconWrapper, null, visible && !disabled ? (React__default.createElement(ChevronUp, { width: 20, height: 20 })) : (React__default.createElement(ChevronDown, { width: 20, height: 20 }))))),
        visible && !disabled && (React__default.createElement(OptionsPopper, Object.assign({ role: "listbox", "data-testid": appendTestId('popper'), ref: setPopperElement, width: popperWidth, maxHeight: maxHeight, style: styles.popper }, attributes.popper),
            React__default.createElement(SearchOptions, { searchOptions: filteredOptions, noResultsText: noResultsText, value: searchValue === '' ? searchValue : debouncedValue, selectedOption: value, focusElement: focusElement, setFocusElement: setFocusElement, onClick: handleOptionChange, multivalue: multivalue }))),
        React__default.createElement(SupportingText, null,
            Boolean(errorText) && showError && !disabled && (React__default.createElement(ErrorMessage, null,
                React__default.createElement(AlertCircle, null),
                errorText)),
            !showError &&
                (typeof assistText === 'string' ? (React__default.createElement(AssistMessage, null, assistText)) : (assistText)))));
}

export { SearchableDropdown };
