import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, extends as _extends, typeof as _typeof } from '../../_virtual/_rollupPluginBabelHelpers.js';
import React__default, { forwardRef, useMemo, useState, useRef, useReducer, useLayoutEffect } from 'react';
import { getItemByFocused, useKeyNavigation } from './hooks/useKeyboardNavigation.js';
import { usePathMaps } from './hooks/usePathMaps.js';
import { ListWrapper, Ul, StyledEmptyState, base } from './Select.styles.js';
import { classes } from './Select.tokens.js';
import { FloatingPopover } from './FloatingPopover.js';
import { SelectNative } from './ui/SelectNative/SelectNative.js';
import { Context } from './Select.context.js';
import { initialItemsTransform } from './utils/initialItemsTransform.js';
import { pathReducer } from './reducers/pathReducer.js';
import { treePathReducer } from './reducers/treePathReducer.js';
import { focusedPathReducer } from './reducers/focusedPathReducer.js';
import { safeUseId } from '../../utils/react.js';
import { useOutsideClick } from '../../hooks/useOutsideClick.js';
import { isEmpty } from '../../utils/isEmpty.js';
import { updateDescendants } from './utils/updateDescendants.js';
import { updateAncestors } from './utils/updateAncestors.js';
import { updateSingleAncestors } from './utils/updateSingleAncestors.js';
import { Target } from './ui/Target/Target.js';
import { TreeList } from './ui/TreeList/TreeList.js';
import { SelectAll } from './ui/SelectAll/SelectAll.js';
import { VirtualList } from './ui/VirtualList/VirtualList.js';
import { Inner } from './ui/Inner/Inner.js';
import { getView } from './utils/getView.js';

var _excluded = ["id", "value", "onChange", "target", "items", "treeView", "arrowPlacement", "placement", "label", "labelPlacement", "placeholder", "helperText", "disabled", "readOnly", "view", "size", "listOverflow", "listHeight", "listMaxHeight", "listWidth", "contentLeft", "contentRight", "onScrollBottom", "onScroll", "chipView", "variant", "portal", "renderValue", "renderItem", "renderSelectionIcon", "status", "onItemSelect", "separator", "closeAfterSelect", "isTargetAmount", "beforeList", "afterList", "zIndex", "name", "defaultValue", "virtual", "onToggle", "chipType", "multiselect", "mode", "shift", "flip", "chipClickArea", "singleLine", "emptyStateDescription", "_offset", "required", "requiredPlacement", "hasRequiredIndicator", "optional", "hintText", "hintTrigger", "hintView", "hintSize", "hintTargetPlacement", "hintPlacement", "hintWidth", "hintHasArrow", "hasHint"];

/**
 * Выпадающий список. Поддерживает выбор одного или нескольких значений.
 */
var selectRoot = function selectRoot(Root) {
  return /*#__PURE__*/forwardRef(function (props, ref) {
    var _getItemByFocused;
    var id = props.id,
      outerValue = props.value,
      _props$target = props.target,
      target = _props$target === void 0 ? 'textfield-like' : _props$target,
      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' : _props$placement,
      label = props.label,
      labelPlacement = props.labelPlacement,
      placeholder = props.placeholder,
      helperText = props.helperText,
      _props$disabled = props.disabled,
      disabled = _props$disabled === void 0 ? false : _props$disabled,
      _props$readOnly = props.readOnly,
      readOnly = _props$readOnly === void 0 ? false : _props$readOnly,
      outerView = props.view,
      size = props.size,
      listHeight = props.listHeight,
      listMaxHeight = props.listMaxHeight,
      listWidth = props.listWidth,
      contentLeft = props.contentLeft,
      contentRight = props.contentRight,
      onScrollBottom = props.onScrollBottom,
      onScroll = props.onScroll,
      chipView = props.chipView,
      _props$variant = props.variant,
      variant = _props$variant === void 0 ? 'normal' : _props$variant,
      portal = props.portal,
      renderValue = props.renderValue,
      renderItem = props.renderItem,
      renderSelectionIcon = props.renderSelectionIcon,
      status = props.status,
      onItemSelect = props.onItemSelect,
      separator = props.separator,
      outerCloseAfterSelect = props.closeAfterSelect,
      isTargetAmount = props.isTargetAmount,
      beforeList = props.beforeList,
      afterList = props.afterList,
      zIndex = props.zIndex,
      name = props.name,
      defaultValue = props.defaultValue,
      _props$virtual = props.virtual,
      virtual = _props$virtual === void 0 ? false : _props$virtual,
      onToggle = props.onToggle,
      multiselect = props.multiselect,
      _props$mode = props.mode,
      mode = _props$mode === void 0 ? 'default' : _props$mode,
      shift = props.shift,
      flip = props.flip,
      singleLine = props.singleLine,
      emptyStateDescription = props.emptyStateDescription,
      _offset = props._offset,
      required = props.required,
      requiredPlacement = props.requiredPlacement,
      hasRequiredIndicator = props.hasRequiredIndicator,
      optional = props.optional,
      hintText = props.hintText,
      hintTrigger = props.hintTrigger,
      hintView = props.hintView,
      hintSize = props.hintSize,
      hintTargetPlacement = props.hintTargetPlacement,
      hintPlacement = props.hintPlacement,
      hintWidth = props.hintWidth,
      hintHasArrow = props.hintHasArrow,
      rest = _objectWithoutProperties(props, _excluded);
    var transformedItems = useMemo(function () {
      return initialItemsTransform(items || []);
    }, [items]);

    // Создаем структуры для быстрой работы с деревом
    var _usePathMaps = usePathMaps(transformedItems),
      _usePathMaps2 = _slicedToArray(_usePathMaps, 5),
      pathMap = _usePathMaps2[0],
      focusedToValueMap = _usePathMaps2[1],
      valueToCheckedMap = _usePathMaps2[2],
      valueToItemMap = _usePathMaps2[3],
      valueToPathMap = _usePathMaps2[4];
    var _useState = useState(props.multiselect ? [] : ''),
      _useState2 = _slicedToArray(_useState, 2),
      internalValue = _useState2[0],
      setInternalValue = _useState2[1];
    var value = outerValue !== null && outerValue !== undefined ? outerValue : internalValue;
    var floatingPopoverRef = useRef(null);

    // Состояния дерева элементов
    var _useReducer = useReducer(pathReducer, []),
      _useReducer2 = _slicedToArray(_useReducer, 2),
      path = _useReducer2[0],
      dispatchPath = _useReducer2[1];
    var _useReducer3 = useReducer(treePathReducer, {}),
      _useReducer4 = _slicedToArray(_useReducer3, 2),
      treePath = _useReducer4[0],
      dispatchTreePath = _useReducer4[1];
    var _useReducer5 = useReducer(focusedPathReducer, []),
      _useReducer6 = _slicedToArray(_useReducer5, 2),
      focusedPath = _useReducer6[0],
      dispatchFocusedPath = _useReducer6[1];
    var _useState3 = useState(valueToCheckedMap),
      _useState4 = _slicedToArray(_useState3, 2),
      checked = _useState4[0],
      setChecked = _useState4[1];
    var isCurrentListOpen = Boolean(path[0]);
    var activeDescendantItemValue = ((_getItemByFocused = getItemByFocused(focusedPath, focusedToValueMap)) === null || _getItemByFocused === void 0 ? void 0 : _getItemByFocused.value.toString()) || '';
    var closeAfterSelect = outerCloseAfterSelect !== null && outerCloseAfterSelect !== void 0 ? outerCloseAfterSelect : !props.multiselect;
    var treeId = safeUseId();
    var listWrapperRef = useRef(null);
    var view = target === 'textfield-like' && (disabled || readOnly) ? 'default' : getView(status, outerView);
    var rootRef = useRef(null);

    // Собираем объект с пропсами для required и прокидываем их напрямую в компонент Textfield.
    var requiredProps = props.target === 'button-like' ? undefined : {
      required: required,
      requiredPlacement: requiredPlacement,
      hasRequiredIndicator: hasRequiredIndicator,
      optional: optional
    };

    // Собираем объект с пропсами для hint и прокидываем их напрямую в компонент Textfield.
    var hintProps = props.target === 'button-like' ? undefined : {
      hintText: hintText,
      hintTrigger: hintTrigger,
      hintView: hintView,
      hintSize: hintSize,
      hintTargetPlacement: hintTargetPlacement,
      hintPlacement: hintPlacement,
      hintWidth: hintWidth,
      hintHasArrow: hintHasArrow
    };

    /* Логика работы при клике за пределами выпадающего списка */
    useOutsideClick(function () {
      if (!isCurrentListOpen) {
        return;
      }
      handleListToggle(false);
    }, [floatingPopoverRef, listWrapperRef]);
    var onChange = function onChange(newValue, item) {
      if (props.onChange) {
        // Условие для отправки если компонент используется без формы.
        if (!props.name && (typeof newValue === 'string' || Array.isArray(newValue))) {
          props.onChange(newValue, item || null);
        }

        // Условие для отправки если компонент используется с формой.
        // Убрать условие "typeof ref === 'function'" в PLASMA 2.0
        if (props.name && _typeof(newValue) === 'object' && !Array.isArray(newValue)) {
          props.onChange(newValue, item || null);
        }
      }

      // Условие для изменения внутреннего значения (только если newValue строка или массив строк).
      if (typeof newValue === 'string' || Array.isArray(newValue)) {
        setInternalValue(newValue);
      }
    };
    var handleListToggle = function handleListToggle(opened) {
      if (disabled || readOnly) {
        return;
      }
      if (opened) {
        dispatchPath({
          type: 'opened_first_level'
        });
      } else {
        var _rootRef$current;
        dispatchFocusedPath({
          type: 'reset'
        });
        dispatchPath({
          type: 'reset'
        });
        dispatchTreePath({
          type: 'reset'
        });

        // Скроллим чипы к левому краю при закрытии компонента
        var el = rootRef === null || rootRef === void 0 || (_rootRef$current = rootRef.current) === null || _rootRef$current === void 0 ? void 0 : _rootRef$current.querySelector('.input-scrollable-wrapper');
        if (multiselect && value.length > 0 && el) {
          el.scrollLeft = 0;
        }
      }
      if (onToggle) {
        onToggle(opened);
      }
    };
    var handleCheckboxChange = function handleCheckboxChange(item) {
      if (!props.multiselect) {
        return;
      }
      var checkedCopy = new Map(checked);
      switch (checkedCopy.get(item.value)) {
        // Если чекбокс в состоянии indeterminate
        case 'indeterminate':
          {
            updateDescendants(item, checkedCopy, true, valueToItemMap);
            break;
          }
        // Если чекбокс в состоянии checked
        case true:
          {
            updateDescendants(item, checkedCopy, false, valueToItemMap);
            checkedCopy.set(item.value, false);
            break;
          }
        // Если чекбокс в состоянии unchecked
        case false:
          {
            updateDescendants(item, checkedCopy, true, valueToItemMap);
            checkedCopy.set(item.value, true);
            break;
          }
      }
      var newValues = [];
      valueToItemMap.forEach(function (item, key) {
        if (checkedCopy.get(key)) {
          newValues.push(item.value);
        }
      });

      // Оставляем values, которых нет в items.
      if (Array.isArray(value)) {
        value.forEach(function (val) {
          if (!valueToItemMap.has(val)) {
            newValues.push(val);
          }
        });
      }
      if (closeAfterSelect) {
        dispatchPath({
          type: 'reset'
        });
        dispatchFocusedPath({
          type: 'reset'
        });
        dispatchTreePath({
          type: 'reset'
        });
      }
      if (onChange) {
        onChange(newValues, item);
      }
    };
    var handleItemClick = function handleItemClick(item, e) {
      if (!isEmpty(item === null || item === void 0 ? void 0 : item.items)) {
        return;
      }
      if (props.multiselect) {
        handleCheckboxChange(item);
        return;
      }
      if (e) {
        e.stopPropagation();
      }
      var isCurrentChecked = checked.get(item.value);
      if (closeAfterSelect) {
        dispatchPath({
          type: 'reset'
        });
        dispatchFocusedPath({
          type: 'reset'
        });
        dispatchTreePath({
          type: 'reset'
        });
      }

      // Закрываем список, если элемент уже выбран.
      if (mode === 'radio' && isCurrentChecked) {
        return;
      }
      if (onChange) {
        onChange(isCurrentChecked ? '' : item.value, item);
      }
      if (onItemSelect) {
        onItemSelect(item, e);
      }
    };
    var handlePressDown = function handlePressDown(item, e) {
      if (isEmpty(item.items)) {
        handleItemClick(item, e);
      } else if (props.multiselect) {
        handleCheckboxChange(item);
      }
    };
    var handleScroll = function handleScroll(e) {
      if (onScroll) {
        onScroll(e);
      }
      if (!onScrollBottom) return;
      var target = e.target;
      if (target.scrollHeight - target.scrollTop === target.clientHeight) {
        onScrollBottom(e);
      }
    };
    var _useKeyNavigation = useKeyNavigation({
        focusedPath: focusedPath,
        dispatchFocusedPath: dispatchFocusedPath,
        path: path,
        dispatchPath: dispatchPath,
        pathMap: pathMap,
        focusedToValueMap: focusedToValueMap,
        handleListToggle: handleListToggle,
        handlePressDown: handlePressDown,
        treePath: treePath,
        dispatchTreePath: dispatchTreePath,
        treeView: treeView,
        valueToPathMap: valueToPathMap,
        items: transformedItems,
        readOnly: readOnly
      }),
      onKeyDown = _useKeyNavigation.onKeyDown;

    // В данном эффекте мы следим за изменениями value снаружи и вносим коррективы в дерево чекбоксов.
    // Пример: когда юзер очистил value извне, тогда нужно пройтись по элементам и выключить все чекбоксы.
    useLayoutEffect(function () {
      var checkedCopy = new Map(valueToCheckedMap);
      checkedCopy.forEach(function (_, key) {
        checkedCopy.set(key, false);
      });
      if (!isEmpty(value) || typeof value === 'number') {
        if (Array.isArray(value)) {
          value.forEach(function (val) {
            // Только если value находится в items, т.к. value может и не существовать в items.
            if (valueToItemMap.has(val)) {
              checkedCopy.set(val, true);
              updateDescendants(valueToItemMap.get(val), checkedCopy, true);
              updateAncestors(valueToItemMap.get(val), checkedCopy);
            }
          });
        } else {
          // Только если value находится в items, т.к. value может и не существовать в items.
          // eslint-disable-next-line no-lonely-if
          if (valueToItemMap.has(value)) {
            checkedCopy.set(value, 'done');
            updateSingleAncestors(valueToItemMap.get(value), checkedCopy, 'dot');
          }
        }
      }
      setChecked(checkedCopy);

      // В deps мы кладем именно outerValue и internalValue, а не просто value.
      // Т.к. вначале нужно отфильтровать и провалидировать outerValue и результат положить в переменную.
      // А переменную, содержащую сложные типы данных, нельзя помещать в deps.
    }, [outerValue, internalValue, items]);
    useLayoutEffect(function () {
      if (defaultValue) {
        setInternalValue(defaultValue);
      }
    }, [defaultValue]);
    return /*#__PURE__*/React__default.createElement(Root, _extends({
      view: view,
      size: size,
      labelPlacement: labelPlacement,
      chipView: chipView,
      disabled: disabled,
      readOnly: readOnly,
      hintView: hintView,
      hintSize: hintSize,
      id: id,
      ref: rootRef
    }, rest), name && /*#__PURE__*/React__default.createElement(SelectNative, {
      items: valueToItemMap,
      name: name,
      value: internalValue,
      multiselect: props.multiselect,
      onChange: onChange,
      onSetValue: setInternalValue,
      ref: ref
    }), /*#__PURE__*/React__default.createElement(Context.Provider, {
      value: {
        focusedPath: focusedPath,
        checked: checked,
        multiselect: props.multiselect,
        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: isCurrentListOpen,
      onToggle: handleListToggle,
      placement: placement,
      portal: portal,
      listWidth: listWidth,
      offset: _offset,
      target: function target(referenceRef) {
        return /*#__PURE__*/React__default.createElement(Target, {
          ref: name ? null : ref,
          value: value,
          opened: isCurrentListOpen,
          valueToItemMap: valueToItemMap,
          label: label,
          placeholder: placeholder,
          onKeyDown: onKeyDown,
          labelPlacement: labelPlacement,
          size: size,
          contentLeft: contentLeft,
          contentRight: contentRight,
          disabled: disabled,
          readOnly: readOnly,
          renderValue: renderValue,
          selectProps: props,
          inputWrapperRef: referenceRef,
          multiselect: props.multiselect,
          view: view,
          helperText: helperText,
          treeId: treeId,
          activeDescendantItemValue: activeDescendantItemValue,
          isTargetAmount: isTargetAmount,
          onChange: onChange,
          chipView: chipView,
          separator: separator,
          requiredProps: requiredProps,
          hintProps: hintProps
        });
      },
      zIndex: zIndex,
      isInner: false,
      shift: shift,
      flip: flip
    }, /*#__PURE__*/React__default.createElement(Root, _extends({
      view: view,
      size: size,
      labelPlacement: labelPlacement,
      chipView: chipView,
      disabled: disabled,
      readOnly: readOnly
    }, rest), treeView ? /*#__PURE__*/React__default.createElement(TreeList, {
      items: items,
      listMaxHeight: listMaxHeight,
      onScroll: virtual ? undefined : handleScroll,
      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(props.multiselect),
      listMaxHeight: listMaxHeight || listHeight,
      onScroll: virtual ? undefined : handleScroll,
      virtual: virtual
    }, beforeList, props.multiselect && props.selectAllOptions &&
    /*#__PURE__*/
    // TODO: #2004
    React__default.createElement(SelectAll, {
      selectAllOptions: props.selectAllOptions,
      variant: variant
    }), isEmpty(transformedItems) ? /*#__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: transformedItems,
      listMaxHeight: listMaxHeight || listHeight,
      onScroll: onScroll
    }) : transformedItems.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 selectConfig = {
  name: 'Select',
  tag: 'div',
  layout: selectRoot,
  base: base,
  variations: {},
  defaults: {
    view: 'default',
    size: 'm',
    labelPlacement: 'outer',
    chipView: 'default'
  }
};

export { selectConfig, selectRoot };
//# sourceMappingURL=Select.js.map
