import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
import React__default, { forwardRef, useMemo, useRef, useLayoutEffect } from 'react';
import { classes } from './Combobox.tokens.js';
import { FloatingPopover } from './FloatingPopover.js';
import { IconArrowWrapper, StyledArrow, StyledLeftHelper, ListWrapper, Ul, StyledEmptyState, base } from './Combobox.styles.js';
import { base as base$1 } from './variations/_view/base.js';
import { base as base$2 } from './variations/_size/base.js';
import { base as base$3 } from './variations/_readOnly/base.js';
import { SelectNative } from './ui/SelectNative/SelectNative.js';
import { Context } from './Combobox.context.js';
import { initialItemsTransform } from './utils/initialItemsTransform.js';
import { useSelectionMaps } from './hooks/usePathMaps.js';
import { safeUseId } from '../../utils/react.js';
import { useForkRef } from '../../hooks/useForkRef.js';
import { useValue } from './hooks/useValue.js';
import { useComboboxItems } from './hooks/useComboboxItems.js';
import { useListState } from './hooks/useListState.js';
import { useCheckedState } from './hooks/useCheckedState.js';
import { useKeyNavigation, getItemByFocused } from './hooks/useKeyboardNavigation.js';
import { useOutsideClick } from '../../hooks/useOutsideClick.js';
import { useDidMountLayoutEffect } from '../../hooks/useDidMountLayoutEffect.js';
import { defaultFilter } from './utils/filterItems.js';
import { StyledTextField } from './ui/Target/Target.styles.js';
import { TreeList } from './ui/TreeList/TreeList.js';
import { SelectAll } from './ui/SelectAll/SelectAll.js';
import { isEmpty } from '../../utils/isEmpty.js';
import { VirtualList } from './ui/VirtualList/VirtualList.js';
import { Inner } from './ui/Inner/Inner.js';
import { getTextValue } from './utils/getTextValue.js';
import { sizeToIconSize } from './utils/sizeToIconSize.js';
import { getItemId } from './utils/getItemId.js';
import { hasOuterValue } from './utils/hasOuterValue.js';

var _excluded = ["view", "size", "chipView", "hintView", "hintSize", "chipClickArea", "contentLeft", "contentRight", "placeholder", "helperText", "label", "labelPlacement", "keepPlaceholder", "multiple", "value", "defaultValue", "onChange", "isTargetAmount", "targetAmount", "renderValue", "name", "items", "treeView", "arrowPlacement", "placement", "variant", "zIndex", "listMaxHeight", "listWidth", "portal", "textBefore", "textAfter", "renderItem", "renderSelectionIcon", "filter", "closeAfterSelect", "onChangeValue", "filterValue", "onScroll", "onToggle", "beforeList", "afterList", "virtual", "mode", "emptyStateDescription", "flip", "shift", "singleLine", "readOnly", "disabled", "alwaysOpened", "_offset"];

/**
 * Поле ввода с выпадающим списком и возможностью фильтрации и выбора элементов.
 */
var comboboxRoot = function comboboxRoot(Root) {
  return /*#__PURE__*/forwardRef(function (props, ref) {
    var _getItemByFocused;
    var view = props.view,
      size = props.size,
      chipView = props.chipView,
      hintView = props.hintView,
      hintSize = props.hintSize,
      _props$chipClickArea = props.chipClickArea,
      chipClickArea = _props$chipClickArea === void 0 ? 'full' : _props$chipClickArea,
      contentLeft = props.contentLeft,
      contentRight = props.contentRight,
      placeholder = props.placeholder,
      helperText = props.helperText,
      label = props.label,
      labelPlacement = props.labelPlacement,
      keepPlaceholder = props.keepPlaceholder,
      multiple = props.multiple,
      outerValue = props.value,
      defaultValue = props.defaultValue,
      outerOnChange = props.onChange,
      isTargetAmount = props.isTargetAmount,
      targetAmount = props.targetAmount,
      renderValue = props.renderValue,
      name = props.name,
      items = props.items,
      _props$treeView = props.treeView,
      treeView = _props$treeView === void 0 ? false : _props$treeView,
      _props$arrowPlacement = props.arrowPlacement,
      arrowPlacement = _props$arrowPlacement === void 0 ? 'left' : _props$arrowPlacement,
      _props$placement = props.placement,
      placement = _props$placement === void 0 ? 'bottom-start' : _props$placement,
      _props$variant = props.variant,
      variant = _props$variant === void 0 ? 'normal' : _props$variant,
      zIndex = props.zIndex,
      listMaxHeight = props.listMaxHeight,
      listWidth = props.listWidth,
      portal = props.portal,
      textBefore = props.textBefore,
      textAfter = props.textAfter,
      renderItem = props.renderItem,
      renderSelectionIcon = props.renderSelectionIcon,
      filter = props.filter,
      outerCloseAfterSelect = props.closeAfterSelect,
      onChangeValue = props.onChangeValue,
      filterValue = props.filterValue,
      onScroll = props.onScroll,
      onToggle = props.onToggle,
      beforeList = props.beforeList,
      afterList = props.afterList,
      _props$virtual = props.virtual,
      virtual = _props$virtual === void 0 ? false : _props$virtual,
      _props$mode = props.mode,
      mode = _props$mode === void 0 ? 'default' : _props$mode,
      emptyStateDescription = props.emptyStateDescription,
      flip = props.flip,
      shift = props.shift,
      singleLine = props.singleLine,
      _props$readOnly = props.readOnly,
      readOnly = _props$readOnly === void 0 ? false : _props$readOnly,
      _props$disabled = props.disabled,
      disabled = _props$disabled === void 0 ? false : _props$disabled,
      _props$alwaysOpened = props.alwaysOpened,
      alwaysOpened = _props$alwaysOpened === void 0 ? false : _props$alwaysOpened,
      _offset = props._offset,
      rest = _objectWithoutProperties(props, _excluded);

    // Deep copy массива items с добавлением parent-ноды родителя.
    var transformedItems = useMemo(function () {
      return initialItemsTransform(items || []);
    }, [items]);

    // Создаем структуры для быстрой работы с полным деревом.
    var _useSelectionMaps = useSelectionMaps(transformedItems),
      _useSelectionMaps2 = _slicedToArray(_useSelectionMaps, 3),
      valueToCheckedMap = _useSelectionMaps2[0],
      valueToItemMap = _useSelectionMaps2[1],
      valueToPathMap = _useSelectionMaps2[2];

    /**
     * Refs
     */
    var floatingPopoverRef = useRef(null);
    var treeId = safeUseId();
    var listWrapperRef = useRef(null);
    var rootRef = useRef(null);
    var inputRef = useRef(null);
    var inputForkRef = useForkRef(inputRef, ref);

    /**
     * Hooks
     */
    var nativeMode = Boolean(name && !hasOuterValue(outerValue));
    var _useValue = useValue({
        outerValue: outerValue,
        outerOnChange: outerOnChange,
        defaultValue: defaultValue,
        multiple: multiple,
        nativeMode: nativeMode,
        valueToItemMap: valueToItemMap,
        renderValue: renderValue,
        onChangeValue: onChangeValue
      }),
      value = _useValue.value,
      handleChange = _useValue.handleChange,
      textValue = _useValue.textValue,
      setTextValue = _useValue.setTextValue;
    var currentLabel = getTextValue(multiple, value, valueToItemMap, renderValue);
    var _useComboboxItems = useComboboxItems({
        items: transformedItems,
        textValue: textValue,
        currentLabel: currentLabel,
        filter: filter
      }),
      filteredItems = _useComboboxItems.filteredItems,
      _useComboboxItems$fil = _useComboboxItems.filteredMaps,
      filteredPathMap = _useComboboxItems$fil.pathMap,
      filteredFocusedToValueMap = _useComboboxItems$fil.focusedToValueMap,
      filteredValueToPathMap = _useComboboxItems$fil.valueToPathMap;
    var _useListState = useListState({
        disabled: disabled,
        readOnly: readOnly,
        onToggle: onToggle,
        multiple: multiple,
        alwaysOpened: alwaysOpened,
        renderValue: renderValue,
        rootRef: rootRef,
        value: value,
        valueToItemMap: valueToItemMap,
        setTextValue: setTextValue
      }),
      path = _useListState.path,
      treePath = _useListState.treePath,
      focusedPath = _useListState.focusedPath,
      dispatchPath = _useListState.dispatchPath,
      dispatchTreePath = _useListState.dispatchTreePath,
      dispatchFocusedPath = _useListState.dispatchFocusedPath,
      handleListToggle = _useListState.handleListToggle,
      resetListState = _useListState.resetListState,
      isListOpened = _useListState.isListOpened;
    var _useCheckedState = useCheckedState({
        multiple: multiple,
        mode: mode,
        value: value,
        valueToCheckedMap: valueToCheckedMap,
        valueToItemMap: valueToItemMap,
        closeAfterSelect: outerCloseAfterSelect !== null && outerCloseAfterSelect !== void 0 ? outerCloseAfterSelect : !multiple,
        resetListState: resetListState,
        handleChange: handleChange
      }),
      checked = _useCheckedState.checked,
      handleCheckboxChange = _useCheckedState.handleCheckboxChange,
      handleItemClick = _useCheckedState.handleItemClick,
      handlePressDown = _useCheckedState.handlePressDown;
    var _useKeyNavigation = useKeyNavigation({
        focusedPath: focusedPath,
        dispatchFocusedPath: dispatchFocusedPath,
        path: path,
        dispatchPath: dispatchPath,
        pathMap: filteredPathMap,
        focusedToValueMap: filteredFocusedToValueMap,
        handleListToggle: handleListToggle,
        handlePressDown: handlePressDown,
        setTextValue: setTextValue,
        multiple: multiple,
        value: value,
        textValue: textValue,
        valueToItemMap: valueToItemMap,
        treePath: treePath,
        dispatchTreePath: dispatchTreePath,
        treeView: treeView,
        valueToPathMap: filteredValueToPathMap,
        items: filteredItems,
        disabled: disabled,
        readOnly: readOnly
      }),
      onKeyDown = _useKeyNavigation.onKeyDown;

    /**
     * Handlers
     */
    /* Обработчик изменения значения в инпуте */
    var handleTextValueChange = function handleTextValueChange(e) {
      if (!filterValue || filterValue(e.target.value)) {
        setTextValue(e.target.value);
      }
      dispatchPath({
        type: 'opened_first_level'
      });
      dispatchFocusedPath({
        type: 'reset'
      });
    };
    var handleClickArrow = function handleClickArrow(e) {
      handleListToggle(!isListOpened);

      // При клике на иконку закрытия фокус не должен становиться в инпут.
      e.stopPropagation();
    };

    /* Обработчик клика на таргет */
    var handleTargetClick = function handleTargetClick() {
      if (!isListOpened) {
        handleListToggle(true);
      }
    };

    /* Метод получения чипов в определенном формате */
    var getChips = function getChips() {
      if (multiple && Array.isArray(value)) {
        if (value.length === 0) return [];
        if (isTargetAmount) {
          return [{
            value: '_removeAll',
            label: "\u0412\u044B\u0431\u0440\u0430\u043D\u043E ".concat(targetAmount || value.length),
            disabled: value.every(function (val) {
              var _valueToItemMap$get;
              return valueToItemMap === null || valueToItemMap === void 0 || (_valueToItemMap$get = valueToItemMap.get(val)) === null || _valueToItemMap$get === void 0 ? void 0 : _valueToItemMap$get.disabled;
            })
          }];
        }
        return value.map(function (value) {
          var _valueToItemMap$get2, _valueToItemMap$get3;
          var currentLabel = renderValue ? renderValue(valueToItemMap.get(value) || {
            value: value,
            label: value
          }) : ((_valueToItemMap$get2 = valueToItemMap.get(value)) === null || _valueToItemMap$get2 === void 0 ? void 0 : _valueToItemMap$get2.label) || value.toString();
          return {
            value: value,
            label: currentLabel,
            disabled: ((_valueToItemMap$get3 = valueToItemMap.get(value)) === null || _valueToItemMap$get3 === void 0 ? void 0 : _valueToItemMap$get3.disabled) || false
          };
        });
      }
      return [];
    };

    /* Обработчик чипов */
    var handleChipClick = function handleChipClick(chip) {
      if (readOnly || !Array.isArray(value)) return;
      if (isTargetAmount) {
        // При закрытии чипа в режиме isTargetAmount в value оставляем только disabled-элементы
        handleChange(value.filter(function (val) {
          var _valueToItemMap$get4;
          return valueToItemMap === null || valueToItemMap === void 0 || (_valueToItemMap$get4 = valueToItemMap.get(val)) === null || _valueToItemMap$get4 === void 0 ? void 0 : _valueToItemMap$get4.disabled;
        }), null);
      } else {
        handleChange(value.filter(function (val) {
          return val !== chip.value;
        }), valueToItemMap.get(chip.value) || {
          value: chip.value,
          label: chip.label
        });
      }
    };

    /**
     * Effects
     */
    /* Логика работы при клике за пределами выпадающего списка */
    useOutsideClick(function () {
      if (!isListOpened || alwaysOpened) {
        return;
      }
      handleListToggle(false);
    }, [floatingPopoverRef, listWrapperRef]);

    // Эффект для исключительных случаев, когда нужно обновить значение textValue при изменении items,
    // но только если значение textValue совпадает с value в item.
    useLayoutEffect(function () {
      var _valueToItemMap$get5;
      if (!multiple && value && ((_valueToItemMap$get5 = valueToItemMap.get(value)) === null || _valueToItemMap$get5 === void 0 ? void 0 : _valueToItemMap$get5.value) === textValue) {
        var _valueToItemMap$get6;
        setTextValue(((_valueToItemMap$get6 = valueToItemMap.get(value)) === null || _valueToItemMap$get6 === void 0 ? void 0 : _valueToItemMap$get6.label) || value.toString());
      }
    }, [items]);

    // При изменении value нужно возвращать значение в инпуте к исходному.
    useDidMountLayoutEffect(function () {
      setTextValue(getTextValue(multiple, value, valueToItemMap, renderValue));
    }, [value]);

    // Эффект для раскрытия дерева при поиске.
    useLayoutEffect(function () {
      if (treeView) {
        // Если поле ввода стало пустым или если пользователь выбирает элемент,
        // то скрываем все узлы дерева и выходим из эффекта.
        if (textValue === '' || textValue === currentLabel) {
          dispatchTreePath({
            type: 'reset'
          });
          return;
        }

        // Иначе раскрываем все узлы, когда пользователь начинает вводить текст в поле ввода.
        dispatchTreePath({
          type: 'expand_by_key',
          value: {
            filteredItems: filteredItems,
            filterCb: filter || defaultFilter,
            textValue: textValue
          }
        });
      }
    }, [textValue]);

    /**
     * Vars
     */
    var activeDescendantItemValue = ((_getItemByFocused = getItemByFocused(focusedPath, filteredFocusedToValueMap)) === null || _getItemByFocused === void 0 ? void 0 : _getItemByFocused.value) || '';
    var withArrowInverse = isListOpened ? classes.arrowInverse : undefined;
    return /*#__PURE__*/React__default.createElement(Root, {
      size: size,
      view: view,
      labelPlacement: labelPlacement,
      chipView: chipView,
      disabled: disabled,
      readOnly: readOnly,
      name: name,
      hintView: hintView,
      hintSize: hintSize,
      ref: rootRef
    }, nativeMode && /*#__PURE__*/React__default.createElement(SelectNative, {
      items: valueToItemMap,
      name: name,
      value: value,
      multiple: multiple,
      handleChange: handleChange,
      outerOnChange: outerOnChange,
      ref: ref
    }), /*#__PURE__*/React__default.createElement("div", null, /*#__PURE__*/React__default.createElement(Context.Provider, {
      value: {
        focusedPath: focusedPath,
        checked: checked,
        multiple: multiple,
        size: size,
        handleCheckboxChange: handleCheckboxChange,
        handleItemClick: handleItemClick,
        variant: variant,
        renderItem: renderItem,
        renderSelectionIcon: renderSelectionIcon,
        treeId: treeId,
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        // eslint-disable-next-line no-underscore-dangle
        _checkboxAppearance: rest._checkboxAppearance,
        treePath: treePath,
        dispatchTreePath: dispatchTreePath,
        arrowPlacement: arrowPlacement,
        valueToPathMap: valueToPathMap,
        singleLine: singleLine
      }
    }, /*#__PURE__*/React__default.createElement(FloatingPopover, {
      ref: floatingPopoverRef,
      opened: isListOpened,
      placement: placement,
      portal: portal,
      listWidth: listWidth,
      offset: _offset,
      target: function target(referenceRef) {
        return /*#__PURE__*/React__default.createElement("div", {
          onClick: handleTargetClick
        }, /*#__PURE__*/React__default.createElement(StyledTextField, _extends({
          ref: name ? inputRef : inputForkRef,
          inputWrapperRef: referenceRef,
          opened: isListOpened,
          value: textValue,
          onChange: handleTextValueChange,
          size: size,
          view: view,
          disabled: disabled,
          readOnly: readOnly,
          label: label,
          placeholder: placeholder,
          contentLeft: contentLeft,
          contentRight: contentRight || contentRight !== undefined ? contentRight : /*#__PURE__*/React__default.createElement(IconArrowWrapper, {
            disabled: disabled,
            readOnly: readOnly,
            onClick: handleClickArrow,
            className: classes.comboboxTargetArrow
          }, /*#__PURE__*/React__default.createElement(StyledArrow, {
            color: "inherit",
            size: sizeToIconSize(size),
            className: withArrowInverse
          })),
          textBefore: textBefore,
          textAfter: textAfter,
          onKeyDown: onKeyDown,
          leftHelper: helperText && /*#__PURE__*/React__default.createElement(StyledLeftHelper, {
            onClick: function onClick(e) {
              return e.stopPropagation();
            }
          }, helperText),
          role: "combobox",
          "aria-autocomplete": "list",
          "aria-controls": "".concat(treeId, "_tree_level_1"),
          "aria-expanded": isListOpened,
          "aria-activedescendant": activeDescendantItemValue ? getItemId(treeId, activeDescendantItemValue) : '',
          labelPlacement: labelPlacement,
          keepPlaceholder: keepPlaceholder,
          chipView: chipView
        }, multiple ? {
          enumerationType: 'chip',
          _chipClickArea: chipClickArea,
          _chips: getChips(),
          _onChipCloseClick: handleChipClick
        } : {
          enumerationType: 'plain'
        }, rest, {
          _onEnterDisabled: true // Пропс для отключения обработчика Enter внутри Textfield
        })));
      },
      zIndex: zIndex,
      isInner: false,
      shift: shift,
      flip: flip
    }, /*#__PURE__*/React__default.createElement(Root, {
      size: size,
      view: view,
      labelPlacement: labelPlacement,
      chipView: chipView,
      disabled: disabled,
      readOnly: readOnly,
      name: name
    }, treeView ? /*#__PURE__*/React__default.createElement(TreeList, {
      items: filteredItems,
      listMaxHeight: listMaxHeight,
      onScroll: virtual ? undefined : onScroll,
      virtual: virtual,
      beforeList: beforeList,
      afterList: afterList,
      emptyStateDescription: emptyStateDescription
    }) : /*#__PURE__*/React__default.createElement(ListWrapper, {
      ref: listWrapperRef,
      listWidth: listWidth
    }, /*#__PURE__*/React__default.createElement(Ul, {
      role: "tree",
      id: "".concat(treeId, "_tree_level_1"),
      "aria-multiselectable": Boolean(multiple),
      listMaxHeight: listMaxHeight,
      virtual: virtual,
      onScroll: virtual ? undefined : onScroll
    }, beforeList, props.multiple && props.selectAllOptions &&
    /*#__PURE__*/
    // TODO: #2004
    React__default.createElement(SelectAll, {
      selectAllOptions: props.selectAllOptions,
      variant: variant
    }), isEmpty(filteredItems) ? /*#__PURE__*/React__default.createElement(StyledEmptyState, {
      className: classes.emptyStateWrapper,
      description: emptyStateDescription || 'Ничего не найдено'
    }) : /*#__PURE__*/React__default.createElement(React__default.Fragment, null, virtual ? /*#__PURE__*/React__default.createElement(VirtualList, {
      items: filteredItems,
      listMaxHeight: listMaxHeight,
      onScroll: onScroll,
      renderItem: function renderItem(item, index) {
        return /*#__PURE__*/React__default.createElement(Inner, {
          item: item,
          currentLevel: 0,
          path: ['root'],
          dispatchPath: dispatchPath,
          index: index,
          listWidth: listWidth,
          portal: listWrapperRef,
          shift: shift,
          flip: flip
        });
      }
    }) : filteredItems.map(function (item, index) {
      return /*#__PURE__*/React__default.createElement(Inner, {
        key: "".concat(index, "/0"),
        item: item,
        currentLevel: 0,
        path: path,
        dispatchPath: dispatchPath,
        index: index,
        listWidth: listWidth,
        portal: listWrapperRef,
        shift: shift,
        flip: flip
      });
    })), afterList)))))));
  });
};
var comboboxConfig = {
  name: 'Select',
  tag: 'div',
  layout: comboboxRoot,
  base: base,
  variations: {
    view: {
      css: base$1
    },
    size: {
      css: base$2
    },
    readOnly: {
      css: base$3
    }
  },
  defaults: {
    view: 'default',
    size: 'm',
    labelPlacement: 'outer',
    chipView: 'secondary'
  }
};

export { comboboxConfig, comboboxRoot };
