import _createForOfIteratorHelperLoose from "@babel/runtime/helpers/esm/createForOfIteratorHelperLoose";
import _extends from "@babel/runtime/helpers/esm/extends";
import _inheritsLoose from "@babel/runtime/helpers/esm/inheritsLoose";
var _dec, _class, _Select;
import React from 'react';
import invariant from 'invariant';
import { globalObject } from '@skbkontur/global-object';
import debounce from 'lodash.debounce';
import { isKeyArrowDown, isKeyArrowUp, isKeyArrowVertical, isKeyEnter, isKeyEscape, isKeySpace } from "../../../lib/events/keyboard/identifiers";
import { locale } from "../../../lib/locale/decorators";
import { reactGetTextContent } from "../../../lib/reactGetTextContent";
import { Button } from "../../Button";
import { filterProps } from "../../../lib/filterProps";
import { Input } from "../../Input";
import { Menu } from "../../../internal/Menu";
import { MenuItem } from "../../MenuItem";
import { MenuSeparator } from "../../MenuSeparator";
import { RenderLayer } from "../../../internal/RenderLayer";
import { createPropsGetter } from "../../../lib/createPropsGetter";
import { getRandomID, isFunction, isNonNullable, isReactUINode } from "../../../lib/utils";
import { ThemeContext } from "../../../lib/theming/ThemeContext";
import { CommonWrapper } from "../../../internal/CommonWrapper";
import { MobilePopup } from "../../../internal/MobilePopup";
import { cx } from "../../../lib/theming/Emotion";
import { responsiveLayout } from "../../ResponsiveLayout/decorator";
import { getRootNode, rootNode } from "../../../lib/rootNode";
import { ThemeFactory } from "../../../lib/theming/ThemeFactory";
import { styles as linkStyles } from "../../Link/Link.styles";
import { Popup } from "../../../internal/Popup";
import { ZIndex } from "../../../internal/ZIndex";
import { getMenuPositions } from "../../../lib/getMenuPositions";
import { withSize } from "../../../lib/size/SizeDecorator";
import { ArrowDownIcon } from "../ArrowDownIcon";
import { Item } from "../Item";
import { SelectLocaleHelper } from "../locale";
import { styles } from "../Select.styles";
import { getSelectTheme } from "../selectTheme";
import { SelectDataTids } from "../tids";
export * from "../tids";
var PASS_BUTTON_PROPS = {
  id: true,
  disabled: true,
  error: true,
  use: true,
  size: true,
  warning: true,
  corners: true,
  onMouseEnter: true,
  onMouseLeave: true,
  onMouseOver: true
};
export var SelectIds = {
  menu: SelectDataTids.menu
};

/**
 * Раскрывающийся список позволяет выбрать значение из заранее известного набора вариантов.
 */

export var Select = (_dec = locale('Select', SelectLocaleHelper), responsiveLayout(_class = rootNode(_class = _dec(_class = withSize(_class = (_Select = /*#__PURE__*/function (_React$Component) {
  function Select() {
    var _this;
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
    _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
    _this.state = {
      opened: false,
      value: _this.props.defaultValue,
      searchPattern: ''
    };
    _this.menuId = SelectIds.menu + getRandomID();
    _this.buttonElement = null;
    _this.getProps = createPropsGetter(Select.defaultProps);

    /** Открывает раскрывающийся список.
     * @public
     */
    _this.open = function () {
      if (!_this.state.opened) {
        _this.setState({
          opened: true
        });
        if (_this.props.onOpen) {
          _this.props.onOpen();
        }
      }
    };

    /** Закрывает раскрывающийся список.
     * @public
     */
    _this.close = function () {
      if (_this.state.opened) {
        _this.setState({
          opened: false,
          searchPattern: ''
        });
        if (_this.props.onClose) {
          _this.props.onClose();
        }
      }
    };

    /** Программно устанавливает фокус на кнопку.
     * Появляется фокусная рамка, элемент получает клавиатурные события и воспринимается как текущий элемент для чтения скринридерами.
     * @public
     */
    _this.focus = function () {
      if (_this.buttonElement && _this.buttonElement.focus) {
        _this.buttonElement.focus();
      }
    };
    _this.getDefaultButtonParams = function () {
      var _this$renderLabel = _this.renderLabel(),
        label = _this$renderLabel.label,
        isPlaceholder = _this$renderLabel.isPlaceholder;
      var buttonParams = {
        opened: _this.state.opened,
        label: label,
        isPlaceholder: isPlaceholder,
        onClick: _this.toggle,
        onKeyDown: _this.handleKey,
        size: _this.size,
        disabled: _this.getProps().disabled
      };
      return buttonParams;
    };
    _this.getSearch = function () {
      return /*#__PURE__*/(
        React.createElement("div", {
          className: styles.search(),
          onKeyDown: _this.handleKey
        }, /*#__PURE__*/
        React.createElement(Input, {
          ref: _this.debouncedFocusInput,
          onValueChange: _this.handleSearch,
          width: "100%"
        }))
      );
    };
    _this.getMobileSearch = function () {
      return /*#__PURE__*/(
        React.createElement(Input, {
          autoFocus: true,
          value: _this.state.searchPattern,
          ref: _this.debouncedFocusInput,
          onValueChange: _this.handleSearch,
          width: "100%"
        })
      );
    };
    _this.getMenuItems = function (value) {
      var isMobile = _this.isMobileLayout;
      var size = _this.size;
      return _this.mapItems(function (iValue, item, i, comment) {
        if (isFunction(item)) {
          var element = item();
          if ( /*#__PURE__*/React.isValidElement(element)) {
            return /*#__PURE__*/React.cloneElement(element, {
              key: i,
              isMobile: isMobile,
              size: size
            });
          }
          return null;
        }
        if ( /*#__PURE__*/React.isValidElement(item)) {
          if (isReactUINode('MenuItem', item)) {
            return /*#__PURE__*/React.cloneElement(item, {
              key: i,
              isMobile: isMobile,
              size: size
            });
          }
          if (isReactUINode('MenuHeader', item)) {
            return /*#__PURE__*/React.cloneElement(item, {
              size: size
            });
          }
          return /*#__PURE__*/React.cloneElement(item, {
            key: i
          });
        }
        return /*#__PURE__*/(
          React.createElement(MenuItem, {
            key: i,
            state: _this.areValuesEqual(iValue, value) ? 'selected' : null,
            onClick: _this.select.bind(_this, iValue),
            comment: comment,
            isMobile: isMobile,
            size: _this.size
          }, _this.getProps().renderItem(iValue, item))
        );
      });
    };
    _this.popupGetParent = function () {
      return getRootNode(_this);
    };

    // fix cases when an Input is rendered in portal
    // https://github.com/skbkontur/retail-ui/issues/1995
    _this.focusInput = function (input) {
      return input == null ? void 0 : input.focus();
    };
    _this.debouncedFocusInput = debounce(_this.focusInput);
    _this.refMenu = function (menu) {
      _this.menu = menu;
    };
    _this.toggle = function () {
      if (_this.state.opened) {
        _this.close();
      } else {
        _this.open();
      }
    };
    _this.handleKey = function (e) {
      if (!_this.state.opened) {
        if (isKeySpace(e) || isKeyArrowVertical(e)) {
          e.preventDefault();
          _this.open();
        }
      } else {
        switch (true) {
          case isKeyEscape(e):
            _this.focus();
            _this.close();
            break;
          case isKeyArrowUp(e):
            e.preventDefault();
            if (_this.menu) {
              _this.menu.up();
            }
            break;
          case isKeyArrowDown(e):
            e.preventDefault();
            if (_this.menu) {
              _this.menu.down();
            }
            break;
          case isKeyEnter(e):
            e.preventDefault(); // To prevent form submission.
            if (_this.menu) {
              _this.menu.enter(e);
            }
            break;
        }
      }
      if (_this.props.onKeyDown) {
        _this.props.onKeyDown(e);
      }
    };
    _this.handleSearch = function (value) {
      var _this$menu;
      _this.setState({
        searchPattern: value
      });
      (_this$menu = _this.menu) == null || _this$menu.highlightItem(0);
    };
    _this.buttonRef = function (element) {
      _this.buttonElement = element;
    };
    _this.getButton = function (buttonParams) {
      var _props$ariaLabel;
      var button = _this.props._renderButton ? _this.props._renderButton(buttonParams) : _this.renderDefaultButton(buttonParams);
      var buttonElement = React.Children.only(button);
      return /*#__PURE__*/React.isValidElement(buttonElement) ? /*#__PURE__*/
      React.cloneElement(buttonElement, {
        ref: _this.buttonRef,
        onFocus: _this.props.onFocus,
        onBlur: _this.props.onBlur,
        size: _this.size,
        'aria-describedby': _this.props['aria-describedby'],
        'aria-expanded': _this.state.opened ? 'true' : 'false',
        'aria-controls': _this.menuId,
        'aria-label': (_props$ariaLabel = buttonElement.props['aria-label']) != null ? _props$ariaLabel : _this.props['aria-label']
      }) : buttonElement;
    };
    return _this;
  }
  _inheritsLoose(Select, _React$Component);
  var _proto = Select.prototype;
  _proto.componentDidUpdate = function componentDidUpdate(_prevProps, prevState) {
    if (!prevState.opened && this.state.opened) {
      globalObject.addEventListener == null || globalObject.addEventListener('popstate', this.close);
    }
    if (prevState.opened && !this.state.opened) {
      globalObject.removeEventListener == null || globalObject.removeEventListener('popstate', this.close);
    }
  };
  _proto.render = function render() {
    var _this2 = this;
    return /*#__PURE__*/React.createElement(ThemeContext.Consumer, null, function (theme) {
      _this2.theme = ThemeFactory.create({
        menuOffsetY: theme.selectMenuOffsetY
      }, theme);
      return /*#__PURE__*/React.createElement(ThemeContext.Provider, {
        value: _this2.theme
      }, _this2.renderMain());
    });
  };
  _proto.getMenuRenderer = function getMenuRenderer() {
    if (this.props.disabled) {
      return null;
    }
    if (this.isMobileLayout) {
      return this.renderMobileMenu();
    }
    if (this.state.opened) {
      return this.renderMenu();
    }
    return null;
  };
  _proto.renderMain = function renderMain() {
    var _this$getProps$dataT, _cx;
    var buttonParams = this.getDefaultButtonParams();
    var dataTid = (_this$getProps$dataT = this.getProps()['data-tid']) != null ? _this$getProps$dataT : SelectDataTids.root;
    var button = /*#__PURE__*/React.createElement(ThemeContext.Provider, {
      value: getSelectTheme(this.theme, this.props)
    }, this.getButton(buttonParams));
    var isMobile = this.isMobileLayout;
    var style = {
      width: this.props.width,
      maxWidth: this.props.maxWidth || undefined
    };
    var root = /*#__PURE__*/React.createElement("span", {
      "data-tid": dataTid,
      className: cx((_cx = {}, _cx[styles.root()] = true, _cx[styles.rootMobile(this.theme)] = isMobile, _cx)),
      style: style
    }, button, this.getMenuRenderer());
    return /*#__PURE__*/React.createElement(CommonWrapper, _extends({
      rootNodeRef: this.setRootNode
    }, this.props), /*#__PURE__*/React.createElement(RenderLayer, {
      onClickOutside: this.close,
      onFocusOutside: this.close,
      active: isMobile ? false : this.state.opened
    }, root));
  };
  _proto.renderLabel = function renderLabel() {
    var _this$props$placehold, _this$locale;
    var value = this.getValue();
    var item = this.getItemByValue(value);
    if (isNonNullable(value)) {
      return {
        label: this.getProps().renderValue(value, item),
        isPlaceholder: false
      };
    }
    return {
      label: /*#__PURE__*/React.createElement("span", null, (_this$props$placehold = this.props.placeholder) != null ? _this$props$placehold : (_this$locale = this.locale) == null ? void 0 : _this$locale.placeholder),
      isPlaceholder: true
    };
  };
  _proto.getLeftIconClass = function getLeftIconClass(size) {
    if (this.getProps().use === 'link') {
      return styles.leftIconLink(this.theme);
    }
    switch (size) {
      case 'large':
        return styles.leftIconLarge(this.theme);
      case 'medium':
        return styles.leftIconMedium(this.theme);
      case 'small':
      default:
        return styles.leftIconSmall(this.theme);
    }
  };
  _proto.renderDefaultButton = function renderDefaultButton(params) {
    var _cx2, _cx3, _cx4;
    var buttonProps = _extends({}, filterProps(this.props, PASS_BUTTON_PROPS), {
      align: 'left',
      disabled: this.props.disabled,
      width: '100%',
      onClick: params.onClick,
      onKeyDown: params.onKeyDown,
      active: params.opened,
      size: params.size
    });
    var use = this.getProps().use;
    var labelProps = {
      'data-tid': SelectDataTids.label,
      className: cx((_cx2 = {}, _cx2[styles.label()] = use !== 'link', _cx2[styles.placeholder(this.theme)] = params.isPlaceholder, _cx2[styles.customUsePlaceholder()] = params.isPlaceholder && use !== 'default', _cx2[styles.placeholderDisabled(this.theme)] = params.isPlaceholder && this.props.disabled, _cx2)),
      style: {
        paddingRight: this.getSelectIconGap()
      }
    };
    var useIsCustom = use !== 'default';
    var icon = /*#__PURE__*/React.createElement(ArrowDownIcon, {
      size: this.size
    });
    return /*#__PURE__*/React.createElement(Button, buttonProps, /*#__PURE__*/React.createElement("div", {
      className: cx(styles.selectButtonContainer(), (_cx3 = {}, _cx3[linkStyles.root(this.theme)] = use === 'link', _cx3))
    }, this.props._icon && /*#__PURE__*/React.createElement("div", {
      className: this.getLeftIconClass(this.size)
    }, this.props._icon), /*#__PURE__*/React.createElement("span", labelProps, params.label), /*#__PURE__*/React.createElement("div", {
      className: cx(styles.arrowWrap(this.theme), (_cx4 = {}, _cx4[styles.arrowDisabled(this.theme)] = this.props.disabled, _cx4[styles.customUseArrow()] = useIsCustom, _cx4))
    }, icon)));
  };
  _proto.getSelectIconGap = function getSelectIconGap() {
    var _this3 = this;
    var getArrowPadding = function getArrowPadding() {
      switch (_this3.size) {
        case 'large':
          return _this3.theme.selectIconGapLarge;
        case 'medium':
          return _this3.theme.selectIconGapMedium;
        case 'small':
        default:
          return _this3.theme.selectIconGapSmall;
      }
    };
    var arrowLeftPadding = parseFloat(getArrowPadding()) || 0;
    return arrowLeftPadding;
  };
  _proto.renderMenu = function renderMenu() {
    var search = this.props.search ? this.getSearch() : null;
    var value = this.getValue();
    var _this$getProps = this.getProps(),
      menuWidth = _this$getProps.menuWidth,
      menuPos = _this$getProps.menuPos,
      menuAlign = _this$getProps.menuAlign,
      positions = _this$getProps.positions;
    return /*#__PURE__*/React.createElement(Popup, {
      opened: true,
      hasShadow: true,
      id: this.menuId,
      "data-tid": SelectDataTids.menu,
      positions: positions != null ? positions : getMenuPositions(menuPos, menuAlign),
      anchorElement: this.popupGetParent(),
      priority: ZIndex.priorities.PopupMenu,
      disablePortal: this.props.disablePortal,
      margin: parseInt(this.theme.menuOffsetY) - 1,
      width: menuWidth,
      minWidth: menuWidth === undefined ? '100%' : undefined,
      popupOffset: this.props.menuOffset
    }, /*#__PURE__*/React.createElement(Menu, {
      hasMargin: false,
      ref: this.refMenu,
      onItemClick: this.close,
      maxHeight: this.props.maxMenuHeight,
      align: menuAlign
    }, search, this.getMenuItems(value)));
  };
  _proto.renderMobileMenu = function renderMobileMenu() {
    var search = this.props.search ? this.getMobileSearch() : null;
    var value = this.getValue();
    return /*#__PURE__*/React.createElement(MobilePopup, {
      headerChildComponent: search,
      caption: this.props.mobileMenuHeaderText,
      onCloseRequest: this.close,
      opened: this.state.opened
    }, /*#__PURE__*/React.createElement(Menu, {
      onItemClick: this.close,
      disableScrollContainer: true,
      maxHeight: 'auto'
    }, this.getMenuItems(value)));
  };
  _proto.select = function select(value) {
    this.focus();
    this.setState({
      opened: false,
      value: value
    });
    if (!this.areValuesEqual(this.getValue(), value)) {
      var _this$props$onValueCh, _this$props;
      (_this$props$onValueCh = (_this$props = this.props).onValueChange) == null || _this$props$onValueCh.call(_this$props, value);
    }
  };
  _proto.getValue = function getValue() {
    if (this.props.value !== undefined) {
      return this.props.value;
    }
    return this.state.value;
  };
  _proto.mapItems = function mapItems(fn) {
    var items = this.props.items;
    if (!items) {
      return [];
    }
    var pattern = this.state.searchPattern && this.state.searchPattern.toLowerCase();
    var result = [];
    var index = 0;
    for (var _iterator = _createForOfIteratorHelperLoose(items), _step; !(_step = _iterator()).done;) {
      var entry = _step.value;
      var _normalizeEntry = normalizeEntry(entry),
        value = _normalizeEntry[0],
        item = _normalizeEntry[1],
        comment = _normalizeEntry[2];
      if (!pattern || this.getProps().filterItem(value, item, pattern)) {
        result.push(fn(value, item, index, comment));
        ++index;
      }
    }
    return result;
  };
  _proto.getItemByValue = function getItemByValue(value) {
    if (value === null || value === undefined) {
      return null;
    }
    var items = this.props.items || [];
    for (var _iterator2 = _createForOfIteratorHelperLoose(items), _step2; !(_step2 = _iterator2()).done;) {
      var entry = _step2.value;
      var _normalizeEntry2 = normalizeEntry(entry),
        itemValue = _normalizeEntry2[0],
        item = _normalizeEntry2[1];
      if (this.areValuesEqual(itemValue, value)) {
        return item;
      }
    }
    return null;
  };
  _proto.areValuesEqual = function areValuesEqual(value1, value2) {
    return isNonNullable(value1) && isNonNullable(value2) && this.getProps().areValuesEqual(value1, value2);
  };
  return Select;
}(React.Component), _Select.__KONTUR_REACT_UI__ = 'Select', _Select.displayName = 'Select', _Select.defaultProps = {
  renderValue: renderValue,
  renderItem: renderItem,
  areValuesEqual: areValuesEqual,
  filterItem: filterItem,
  use: 'default'
}, _Select.Item = Item, _Select.SEP = function () {
  return /*#__PURE__*/React.createElement(MenuSeparator, null);
}, _Select.staticElement = function (element) {
  invariant( /*#__PURE__*/React.isValidElement(element) || typeof element === 'function', 'Select.staticElement(element) expects element to be a valid react element.');
  return element;
}, _Select)) || _class) || _class) || _class) || _class);
function renderValue(value, item) {
  return item;
}
function renderItem(value, item) {
  return item;
}
function areValuesEqual(value1, value2) {
  return value1 === value2;
}
function normalizeEntry(entry) {
  if (Array.isArray(entry)) {
    return entry;
  }
  return [entry, entry, undefined];
}
var getTextFromItem = function getTextFromItem(item) {
  if (typeof item === 'string') {
    return item;
  }
  if (isFunction(item)) {
    return getTextFromItem(item());
  }
  if ( /*#__PURE__*/React.isValidElement(item)) {
    return reactGetTextContent(item);
  }
  if (typeof item === 'number') {
    return item.toString(10);
  }
  return '';
};
function filterItem(value, item, pattern) {
  if (item === Select.SEP) {
    return false;
  }
  var itemText = getTextFromItem(item);
  if (!itemText) {
    return false;
  }
  return itemText.toLowerCase().indexOf(pattern) !== -1;
}