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 Close from '../../../icons/Close.js';
import Search from '../../../icons/Search.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 { IconWrapper, InputWrapper, Input, CloseWrapper } from './styles.js';
import { popperOptions } from './utils.js';

function SearchableDropdown(_a) {
    var _b;
    var { variant, id, className, name, label, required, optionalText, errorText, assistText, value, placeholder, width, hasError = false, options, debounceDelay = 500, noResultsText, onChange, onOpen, onClose, onFocus, onBlur, onTextChange, disabled = false, maxHeight = 300, touched } = _a, props = __rest(_a, ["variant", "id", "className", "name", "label", "required", "optionalText", "errorText", "assistText", "value", "placeholder", "width", "hasError", "options", "debounceDelay", "noResultsText", "onChange", "onOpen", "onClose", "onFocus", "onBlur", "onTextChange", "disabled", "maxHeight", "touched"]);
    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 [selectedOption, setSelectedOption] = useState(value);
    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) {
            closePopper();
            setSearchValue(opt.label);
            setSelectedOption(opt);
            onChange(opt);
            setFocusElement(-1);
        }
    };
    const handleInputChange = (event) => {
        if (!visible)
            openPopper();
        const value = event.target.value;
        if (value === '')
            setFilteredOptions(options);
        setSearchValue(value);
        onTextChange && onTextChange(value);
    };
    const handleInputFocus = () => {
        if (!visible && searchValue === '')
            openPopper();
        onFocus && onFocus();
    };
    const handleClear = (event) => {
        if (!disabled) {
            event.preventDefault();
            setFilteredOptions(options);
            setSearchValue('');
            onChange(null);
            setSelectedOption(null);
            openPopper();
        }
    };
    const handleBlur = () => {
        if (searchValue !== '' && filteredOptions.length >= 1 && !selectedOption) {
            setSearchValue(filteredOptions[0].label);
        }
        else if (!selectedOption) {
            setSearchValue('');
        }
        onBlur && onBlur();
    };
    const showClearIcon = () => {
        return searchValue.length > 0 || selectedOption !== null;
    };
    useEffect(() => {
        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(IconWrapper, null,
                React__default.createElement(Search, { width: 24, height: 24 })),
            React__default.createElement(InputWrapper, null,
                React__default.createElement(Input, { id: id || `input-${name}`, ref: inputRef, type: "text", "data-testid": appendTestId(), variant: variant, disabled: disabled, placeholder: placeholder, "aria-haspopup": "true", autoComplete: "off", value: searchValue, onChange: handleInputChange, onBlur: handleBlur, onFocus: handleInputFocus })),
            showClearIcon() && (React__default.createElement(CloseWrapper, { disabled: disabled, onMouseDown: handleClear },
                React__default.createElement(Close, { width: 24, height: 24 })))),
        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, focusElement: focusElement, setFocusElement: setFocusElement, onClick: handleOptionChange }))),
        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 };
