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 { useKeyPress } from '../../../hooks/useKeyPress.js';
import AlertCircle from '../../../icons/AlertCircle.js';
import ChevronDown from '../../../icons/ChevronDown.js';
import { slugify, getId } from '../../../utils/index.js';
import { Wrapper, LabelWrapper, Label, Text, Border, SupportingText, ErrorMessage, AssistMessage } from '../styles.js';
import { DropdownPrefix, SelectInput, OptionsPopper, OptionItem, OptionItemLabel } from './styles.js';
import { MultiValueList } from './components/MultiValueList.js';
import { Checkbox } from '../checkbox/Checkbox.js';

function Dropdown(_a) {
    var _b;
    var { variant, id, name, label, required, placeholder, hasError = false, errorText, optionalText, prefix, assistText, options, onOpen, onClose, onFocus, onBlur, disabled = false, maxHeight = 300, touched, width, noMargin = false } = _a, props = __rest(_a, ["variant", "id", "name", "label", "required", "placeholder", "hasError", "errorText", "optionalText", "prefix", "assistText", "options", "onOpen", "onClose", "onFocus", "onBlur", "disabled", "maxHeight", "touched", "width", "noMargin"]);
    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 [focusOption, setFocusOption] = useState(null);
    const [showError, setShowError] = useState(false);
    const { value, multivalue, onChange } = props;
    const [refElementHeight, setRefElementHeight] = useState(referenceElement === null || referenceElement === void 0 ? void 0 : referenceElement.clientHeight);
    useEffect(() => {
        const composeError = typeof touched === 'undefined' ? hasError : hasError && touched;
        setShowError(composeError);
    }, [hasError, touched]);
    const { styles, attributes, forceUpdate } = usePopper(referenceElement, popperElement, {
        placement: 'bottom',
        modifiers: [
            {
                name: 'offset',
                options: {
                    offset: [0, 2],
                },
            },
            { name: 'preventOverflow', options: { padding: { top: 8 } } },
            { name: 'flip', options: { padding: { top: 8 } } },
        ],
    });
    const { containerRef } = useOnClickOutside(() => setVisibility(false));
    const spacePressed = useKeyPress('Space', containerRef);
    const openPopper = () => {
        if (disabled)
            return;
        setVisibility(true);
        onOpen && onOpen();
    };
    const closePopper = () => {
        if (disabled)
            return;
        setVisibility(false);
        setFocusOption(null);
        onClose && onClose();
    };
    const togglePopper = () => (visible ? closePopper() : openPopper());
    useEffect(() => {
        if (inputRef && inputRef.current) {
            if (visible) {
                inputRef.current.focus();
                onFocus && onFocus();
            }
            else {
                inputRef.current.blur();
            }
        }
    }, [visible]);
    useEffect(() => {
        if (containerRef && containerRef.current) {
            setPopperWidth(containerRef.current.clientWidth);
        }
    }, [(_b = containerRef.current) === null || _b === void 0 ? void 0 : _b.clientWidth]);
    const toggleMultivalueItem = (item) => {
        if (!multivalue) {
            return [];
        }
        const hasItem = value.find((v) => v.value === item.value);
        if (hasItem) {
            return [...value.filter((v) => v.value !== item.value)];
        }
        else {
            return [...value, item];
        }
    };
    useEffect(() => {
        if (spacePressed && focusOption) {
            if (!multivalue) {
                onChange(focusOption);
            }
            else {
                onChange(toggleMultivalueItem(focusOption));
            }
            !multivalue && closePopper();
        }
    }, [spacePressed]);
    useEffect(() => {
        !multivalue && setVisibility(false);
    }, [disabled, value, options, hasError, errorText]);
    const onRemove = (item) => {
        if (multivalue) {
            onChange([...value.filter((v) => String(v.value) !== String(item))]);
        }
    };
    const handleClick = (item) => {
        if (!multivalue) {
            onChange(item);
        }
        else {
            onChange(toggleMultivalueItem(item));
        }
        !multivalue && closePopper();
    };
    const onElementFocus = (op) => () => {
        setFocusOption(op);
    };
    useEffect(() => {
        setTimeout(() => {
            if ((referenceElement === null || referenceElement === void 0 ? void 0 : referenceElement.clientHeight) !== refElementHeight && multivalue) {
                setRefElementHeight(referenceElement === null || referenceElement === void 0 ? void 0 : referenceElement.clientHeight);
                if (typeof forceUpdate === 'function') {
                    forceUpdate();
                }
            }
        });
    }, [referenceElement === null || referenceElement === void 0 ? void 0 : referenceElement.clientHeight, refElementHeight, handleClick]);
    if (!id && label) {
        id = `input-${slugify(label)}`;
    }
    const appendTestId = getId(props['data-testid']);
    const appendTrackId = getId(props['data-trackid']);
    const getInput = () => {
        if (multivalue) {
            return (React__default.createElement(MultiValueList, { values: value, onRemove: onRemove, placeholder: placeholder }));
        }
        else if (!multivalue && value.label) {
            return value.label;
        }
        return placeholder;
    };
    return (React__default.createElement(Wrapper, { ref: containerRef, "data-testid": appendTestId('dropdown'), "data-trackid": appendTrackId('dropdown'), width: width, noMargin: noMargin },
        React__default.createElement(LabelWrapper, { disabled: disabled, hasLabel: Boolean(label === null || label === void 0 ? void 0 : label.length) },
            label && (React__default.createElement(Label, { htmlFor: id, disabled: disabled }, label)),
            !required && React__default.createElement(Text, null, optionalText)),
        React__default.createElement(Border, { hasError: showError, disabled: disabled },
            Boolean(prefix) && (React__default.createElement(DropdownPrefix, { "data-testid": appendTestId('prefix'), hasValue: Boolean(multivalue ? value.length > 0 : value.value) }, prefix)),
            React__default.createElement(SelectInput, { ref: setReferenceElement, id: id, role: "button", "data-testid": appendTestId(), "data-trackid": appendTrackId(), "aria-haspopup": "true", "aria-expanded": visible, onClick: togglePopper, variant: variant, disabled: disabled, "aria-label": label ? undefined : props['aria-label'], hasText: Boolean((multivalue ? value.length > 0 : value.label) || placeholder), onBlur: onBlur },
                getInput(),
                React__default.createElement("input", { ref: inputRef, name: name, readOnly: true }),
                React__default.createElement(ChevronDown, { width: 20, height: 20 }))),
        visible && (React__default.createElement(OptionsPopper, Object.assign({ role: "listbox", ref: setPopperElement, width: popperWidth, maxHeight: maxHeight, style: styles.popper }, attributes.popper, { "data-testid": "options-dropdown" }), options.map((op) => !op.isHidden && (React__default.createElement(OptionItem, { tabIndex: 0, role: "option", isSelected: multivalue
                ? value.some((v) => v.value === op.value)
                : op.value === value.value, isDisabled: op.isDisabled, key: String(op.value), onClick: () => !op.isDisabled && handleClick(op), onFocus: onElementFocus(op), "data-trackid": op['data-trackid'], "data-testid": op['data-testid'], "aria-label": op['aria-label'], isMultivalue: multivalue },
            multivalue ? (React__default.createElement(React__default.Fragment, null,
                React__default.createElement(Checkbox, { name: name || 'multi-select', value: String(op.value), checked: value.some((v) => v.value === op.value), onChange: () => !op.isDisabled && handleClick(op), tabIndex: -1 }),
                React__default.createElement(OptionItemLabel, { isMultivalue: true }, op.label))) : (React__default.createElement(OptionItemLabel, null, op.label)),
            op.altText && React__default.createElement("div", null, op.altText)))))),
        React__default.createElement(SupportingText, { noMargin: noMargin },
            Boolean(errorText) && showError && !disabled && (React__default.createElement(ErrorMessage, null,
                React__default.createElement(AlertCircle, { width: 20, height: 20 }),
                errorText)),
            !showError &&
                (typeof assistText === 'string' ? (React__default.createElement(AssistMessage, null, assistText)) : (assistText)))));
}

export { Dropdown };
