import _extends from "@babel/runtime/helpers/esm/extends";
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
import _inheritsLoose from "@babel/runtime/helpers/esm/inheritsLoose";
var _class, _CustomComboBox;
import _regeneratorRuntime from "@babel/runtime/regenerator";
import React from 'react';
import ReactDOM from 'react-dom';
import { globalObject } from '@skbkontur/global-object';
import { CancelationError, taskWithDelay } from "../../../lib/utils";
import { fixClickFocusIE } from "../../../lib/events/fixClickFocusIE";
import { CommonWrapper } from "../../CommonWrapper";
import { responsiveLayout } from "../../../components/ResponsiveLayout/decorator";
import { rootNode } from "../../../lib/rootNode";
import { ReactUIFeatureFlagsContext, getFullReactUIFlagsContext } from "../../../lib/featureFlagsContext";
import { withSize } from "../../../lib/size/SizeDecorator";
import { ComboBoxRequestStatus } from "../CustomComboBoxTypes";
import { reducer } from "../CustomComboBoxReducer";
import { ComboBoxView } from "../ComboBoxView";
export * from "../tids";
export var DELAY_BEFORE_SHOW_LOADER = 300;
export var LOADER_SHOW_TIME = 1000;
export var DefaultState = {
  inputChanged: false,
  editing: false,
  items: null,
  loading: false,
  opened: false,
  focused: false,
  textValue: '',
  repeatRequest: function repeatRequest() {
    return undefined;
  },
  requestStatus: ComboBoxRequestStatus.Unknown
};
export var CustomComboBox = responsiveLayout(_class = rootNode(_class = withSize(_class = (_CustomComboBox = /*#__PURE__*/function (_React$PureComponent) {
  function CustomComboBox() {
    var _this;
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
    _this = _React$PureComponent.call.apply(_React$PureComponent, [this].concat(args)) || this;
    _this.state = DefaultState;
    _this.requestId = 0;
    _this.focused = false;
    _this.cancelationToken = null;
    _this.canOpenPopup = true;
    _this.reducer = reducer;
    _this.cancelLoaderDelay = function () {
      return null;
    };

    /**
     * @public
     */
    _this.focus = function (opts) {
      if (_this.props.disabled) {
        return;
      }
      if (opts != null && opts.withoutOpenDropdown) {
        _this.canOpenPopup = false;
      }
      if (_this.input) {
        _this.input.focus();
      } else if (_this.inputLikeText) {
        _this.inputLikeText.focus();
      }
    };

    /**
     * @public
     */
    _this.selectInputText = function () {
      if (_this.props.disabled) {
        return;
      }
      if (_this.input) {
        _this.input.selectAll();
      }
    };

    /**
     * @public
     */
    _this.blur = function () {
      if (_this.props.disabled) {
        return;
      }
      _this.handleBlur();
    };
    _this.dispatch = function (action, sync) {
      if (sync === void 0) {
        sync = true;
      }
      var updateState = function updateState(action) {
        var effects;
        var nextState;
        _this.setState(function (state) {
          var stateAndEffect = _this.reducer(state, _this.props, action);
          var _ref = stateAndEffect instanceof Array ? stateAndEffect : [stateAndEffect, []];
          nextState = _ref[0];
          effects = _ref[1];
          return nextState;
        }, function () {
          effects.forEach(_this.handleEffect);
        });
      };

      // Auto-batching React@18 creates problems that are fixed with flushSync
      // https://github.com/skbkontur/retail-ui/pull/3144#issuecomment-1535235366
      if (sync && React.version.search('18') === 0) {
        ReactDOM.flushSync(function () {
          return updateState(action);
        });
      } else {
        updateState(action);
      }
    };
    _this.handleEffect = function (effect) {
      effect(_this.dispatch, _this.getState, _this.getProps, function () {
        return _this;
      });
    };
    _this.getProps = function () {
      return _this.props;
    };
    _this.getState = function () {
      return _this.state;
    };
    _this.handleValueChange = function (value) {
      _this.dispatch({
        type: 'ValueChange',
        value: value,
        keepFocus: !_this.isMobileLayout
      });
    };
    _this.handleFocus = function () {
      if (_this.focused) {
        return;
      }
      _this.focused = true;
      _this.dispatch({
        type: 'Focus',
        searchOnFocus: _this.canOpenPopup && _this.props.searchOnFocus
      });
      if (!_this.canOpenPopup) {
        _this.canOpenPopup = true;
      }
    };
    _this.handleMobileClose = function () {
      _this.handleInputBlur();
    };
    _this.handleClickOutside = function (e) {
      fixClickFocusIE(e);
      _this.handleBlur();
    };
    _this.handleBlur = function () {
      if (!_this.focused) {
        if (_this.state.opened) {
          _this.close();
        }
        return;
      }
      _this.focused = false;
      // workaround for the similar bug with focusout
      // in Firefox, Chrome and IE
      // https://bugzilla.mozilla.org/show_bug.cgi?id=1363964
      globalObject.setTimeout(function () {
        _this.dispatch({
          type: 'Blur'
        });
      }, 0);
    };
    _this.handleInputBlur = function () {
      // If menu opened, RenderLayer is active and
      // it would call handleFocusOutside
      // In that way handleBlur would be called

      if (_this.state.opened && !_this.isMobileLayout) {
        return;
      }
      _this.handleBlur();
    };
    _this.handleInputClick = function () {
      if (!_this.cancelationToken) {
        _this.dispatch({
          type: 'InputClick'
        });
      }
    };
    return _this;
  }
  _inheritsLoose(CustomComboBox, _React$PureComponent);
  var _proto = CustomComboBox.prototype; /**
                                         * @public
                                         */
  _proto.search = /*#__PURE__*/function () {
    var _search = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(query) {
      var _this2 = this;
      var getItems, cancelPromise, expectingId, items;
      return _regeneratorRuntime.wrap(function _callee$(_context) {
        while (1) switch (_context.prev = _context.next) {
          case 0:
            if (query === void 0) {
              query = this.state.textValue;
            }
            getItems = this.props.getItems;
            cancelPromise = new Promise(function (_, reject) {
              return _this2.cancelationToken = reject;
            });
            this.requestId += 1;
            expectingId = this.requestId;
            if (!this.loaderShowDelay) {
              this.loaderShowDelay = new Promise(function (resolve) {
                var cancelLoader = taskWithDelay(function () {
                  _this2.dispatch({
                    type: 'RequestItems'
                  });
                  globalObject.setTimeout(resolve, LOADER_SHOW_TIME);
                }, DELAY_BEFORE_SHOW_LOADER);
                cancelPromise["catch"](function () {
                  return cancelLoader();
                });
                _this2.cancelLoaderDelay = function () {
                  cancelLoader();
                  resolve();
                };
              });
            }
            _context.prev = 6;
            _context.next = 9;
            return Promise.race([getItems(query), cancelPromise]);
          case 9:
            items = _context.sent;
            if (!this.state.loading) {
              _context.next = 13;
              break;
            }
            _context.next = 13;
            return Promise.race([this.loaderShowDelay, cancelPromise]);
          case 13:
            if (expectingId === this.requestId) {
              this.dispatch({
                type: 'ReceiveItems',
                items: items
              });
            }
            _context.next = 19;
            break;
          case 16:
            _context.prev = 16;
            _context.t0 = _context["catch"](6);
            if (_context.t0 && _context.t0.code === 'CancelationError') {
              this.dispatch({
                type: 'CancelRequest'
              });
            } else if (expectingId === this.requestId) {
              this.dispatch({
                type: 'RequestFailure',
                repeatRequest: function repeatRequest() {
                  _this2.search(query);
                  if (_this2.input) {
                    _this2.input.focus();
                  }
                }
              });
            }
          case 19:
            _context.prev = 19;
            if (expectingId === this.requestId) {
              if (!this.state.loading) {
                this.cancelLoaderDelay();
              }
              this.cancelationToken = null;
              this.loaderShowDelay = null;
            }
            return _context.finish(19);
          case 22:
          case "end":
            return _context.stop();
        }
      }, _callee, this, [[6, 16, 19, 22]]);
    }));
    function search(_x) {
      return _search.apply(this, arguments);
    }
    return search;
  }() /**
      * @public
      */;
  _proto.cancelSearch = function cancelSearch() {
    if (this.cancelationToken) {
      this.cancelationToken(new CancelationError());
    }
  } /**
    * @public
    */;
  _proto.open = function open() {
    this.dispatch({
      type: 'Open'
    });
  } /**
    * @public
    */;
  _proto.close = function close() {
    this.dispatch({
      type: 'Close'
    });
  };
  _proto.render = function render() {
    var _this3 = this;
    var viewProps = {
      align: this.props.align,
      borderless: this.props.borderless,
      disabled: this.props.disabled,
      disablePortal: this.props.disablePortal,
      editing: this.state.editing,
      error: this.props.error,
      items: this.state.items,
      loading: this.state.loading,
      opened: this.state.opened,
      drawArrow: this.props.drawArrow,
      menuPos: this.props.menuPos,
      menuAlign: this.props.menuAlign,
      placeholder: this.props.placeholder,
      size: this.size,
      textValue: this.state.textValue,
      totalCount: this.props.totalCount,
      value: this.props.value,
      showClearIcon: this.props.showClearIcon,
      warning: this.props.warning,
      'aria-describedby': this.props['aria-describedby'],
      'aria-label': this.props['aria-label'],
      id: this.props.id,
      width: this.props.width,
      maxLength: this.props.maxLength,
      maxMenuHeight: this.props.maxMenuHeight,
      leftIcon: this.props.leftIcon,
      rightIcon: this.props.rightIcon,
      inputMode: this.props.inputMode,
      mask: this.props.mask,
      maskChar: this.props.maskChar,
      formatChars: this.props.formatChars,
      onBeforePasteInMask: this.props.onBeforePasteInMask,
      onValueChange: this.handleValueChange,
      onClickOutside: this.handleClickOutside,
      onFocus: this.handleFocus,
      onMobileClose: this.handleMobileClose,
      onFocusOutside: this.handleBlur,
      onInputBlur: this.handleInputBlur,
      onInputValueChange: function onInputValueChange(value) {
        return _this3.dispatch({
          type: 'TextChange',
          value: value
        });
      },
      onInputFocus: this.handleFocus,
      onInputClick: this.handleInputClick,
      onClearCrossClick: function onClearCrossClick() {
        return _this3.dispatch({
          type: 'ClearCrossClick'
        });
      },
      onInputKeyDown: function onInputKeyDown(event) {
        event.persist();
        _this3.dispatch({
          type: 'KeyPress',
          event: event
        });
      },
      onMouseEnter: this.props.onMouseEnter,
      onMouseOver: this.props.onMouseOver,
      onMouseLeave: this.props.onMouseLeave,
      renderItem: this.props.renderItem,
      renderNotFound: this.props.renderNotFound,
      itemWrapper: this.props.itemWrapper,
      renderValue: this.props.renderValue,
      renderTotalCount: this.props.renderTotalCount,
      renderAddButton: this.props.renderAddButton,
      repeatRequest: this.state.repeatRequest,
      requestStatus: this.state.requestStatus,
      refInput: function refInput(input) {
        _this3.input = input;
      },
      refMenu: function refMenu(menu) {
        _this3.menu = menu;
      },
      refInputLikeText: function refInputLikeText(inputLikeText) {
        _this3.inputLikeText = inputLikeText;
      },
      viewMode: this.props.viewMode,
      maxRows: this.props.maxRows
    };
    return /*#__PURE__*/React.createElement(ReactUIFeatureFlagsContext.Consumer, null, function (flags) {
      _this3.featureFlags = getFullReactUIFlagsContext(flags);
      return /*#__PURE__*/React.createElement(CommonWrapper, _this3.props, /*#__PURE__*/React.createElement(ComboBoxView, _extends({}, viewProps, {
        size: _this3.size,
        ref: _this3.setRootNode
      })));
    });
  };
  _proto.componentDidMount = function componentDidMount() {
    this.dispatch({
      type: 'Mount'
    }, false);
    if (this.props.autoFocus) {
      this.focus();
    }
  };
  _proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
    if (prevState.editing && !this.state.editing) {
      this.handleBlur();
    }
    this.dispatch({
      type: 'DidUpdate',
      prevProps: prevProps,
      prevState: prevState,
      fixValueChange: this.featureFlags.comboBoxAllowValueChangeInEditingState
    }, false);
  } /**
    * @public
    */;
  _proto.reset = function reset() {
    this.dispatch({
      type: 'Reset'
    });
  };
  return CustomComboBox;
}(React.PureComponent), _CustomComboBox.__KONTUR_REACT_UI__ = 'CustomComboBox', _CustomComboBox.displayName = 'CustomComboBox', _CustomComboBox)) || _class) || _class) || _class;