import _flatten from "ramda/src/flatten";
import _map from "ramda/src/map";
import _pipe from "ramda/src/pipe";
import _head from "ramda/src/head";
import _pathOr from "ramda/src/pathOr";
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
import React, { useCallback, useContext, useEffect, useMemo, useRef } from 'react';
import { useMachine } from '@xstate/react';
import styled from 'styled-components';
import { useOnClickOutside } from '../../../common/Hooks';
import { ActionsWrapper, FormFieldOrFragment, ListItemWrapper, ListWrapper, ListWrapperWithPortal, SearchWrapper, SelectedValueWrapper } from './lib/wrappers';
import { SelectStateContext, useSelectMachineFromContext } from './lib/context';
import { defaultComponents, defaultComponentsMultiselect, useComponentsWithDefaults } from './lib/defaults';
import { ACTION_TYPES, SelectMachine } from './machine';
import { assert } from '../../../common/utils';
import { useAutofocus, useDelegateKeyDownToMachine, useFocusFromMachine, useIsFirstRender, useMultiRef, useOnBlurAndOnFocus, usePropagateChangesThroughOnChange, useSyncPropsWithMachine } from './lib/hooks';
import { SYMBOL_ALL } from './lib/constants';
import TrackingContext from '../../../common/tracking';
import { getSingleSelectValue } from './lib/utils';
import { Modal, useMedia, Typography } from '../../../index';
var HiddenSelect = styled.select.withConfig({
  displayName: "Select__HiddenSelect",
  componentId: "sc-1ca7aak-0"
})(["display:none;"]);
var noop = function noop() {};
var getValuesForNativeSelect = function getValuesForNativeSelect(selectedItems, isMultiselect) {
  if (isMultiselect) {
    return selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.map(function (x) {
      return x.value;
    });
  }
  var value = getSingleSelectValue(selectedItems);
  return _pathOr(undefined, ['value'], _head(value));
};
var Select = function Select(props) {
  assert(Boolean(props.id), "Input.Select: \"id\" is required.");
  assert(typeof props.value !== 'undefined' ? typeof props.onChange !== 'undefined' : true, "Input.Select: You can't use 'value' prop without onChange. It makes sense only if you want a readonly Input.Select, which is really weird. Don't do that.");
  var trackContext = useContext(TrackingContext);
  var isFirstRender = useIsFirstRender();
  var allOptions = useMemo(function () {
    return _pipe(_map(function (option) {
      return option.options ? [option, option.options] : option;
    }), _flatten)(props.options);
  }, [props.options]);
  var smallScreen = useMedia(function (t) {
    return t.media.lessThan(t.breakpoints.sm);
  });
  var isFullscreenOnMobile = smallScreen && props.fullscreenOnMobile && !props.withPortal;
  var isDisableSearchComponent = smallScreen && !props.showSearch ? true : props.disableSearchComponent;
  var machineHandlers = useMachine(SelectMachine, {
    context: {
      label: props.label,
      error: props.error || '',
      success: props.success || false,
      options: allOptions,
      selectedItems: [],
      disabled: props.disabled || false,
      open: false,
      itemFocusIdx: null,
      placeholder: props.placeholder || '',
      searchQuery: '',
      extraInfo: props.extraInfo || '',
      multiselect: props.multiselect || false,
      lastNavigationType: null,
      visibleOptions: allOptions,
      showSearch: props.showSearch || false,
      id: props.id,
      valueFromProps: props.value,
      uncommittedSelectedItems: [],
      actions: props.actions || [],
      disableSearchComponent: isDisableSearchComponent,
      fullscreenOnMobile: isFullscreenOnMobile || false,
      preventScroll: props.preventScroll || false
    }
  });
  var _machineHandlers = _slicedToArray(machineHandlers, 3),
    machineState = _machineHandlers[0],
    send = _machineHandlers[1],
    service = _machineHandlers[2];
  var currentPropsRef = useRef(props);
  currentPropsRef.current = props;
  useEffect(function () {
    var listener = function listener(e) {
      return trackContext && trackContext.track('Input.Select', e, currentPropsRef.current);
    };
    service.onEvent(listener);
    return function () {
      service.off(listener);
    };
  }, [trackContext, service]);
  useEffect(function () {
    if (!props.onSearchQueryChange) return;
    var listener = function listener(e) {
      return e.type === ACTION_TYPES.SEARCH_QUERY_UPDATE && props.onSearchQueryChange(e);
    };
    service.onEvent(listener);
    return function () {
      service.off(listener);
    };
  }, [service, props.onSearchQueryChange]);
  usePropagateChangesThroughOnChange(machineState, send, props.onChange, isFirstRender);
  useSyncPropsWithMachine({
    searchQuery: props.searchQuery || machineState.context.searchQuery,
    label: props.label,
    options: allOptions,
    placeholder: props.placeholder,
    error: props.error,
    valueFromProps: props.value,
    success: props.success,
    disabled: props.disabled,
    extraInfo: props.extraInfo,
    multiselect: props.multiselect,
    showSearch: props.showSearch || false,
    id: props.id,
    actions: props.actions || [],
    disableSearchComponent: isDisableSearchComponent,
    fullscreenOnMobile: isFullscreenOnMobile || false,
    preventScroll: props.preventScroll || false
  }, [send, props.label, allOptions, props.placeholder, props.error, props.success, props.disabled, props.extraInfo, props.value, props.multiselect, props.showSearch, props.id, props.actions, props.searchQuery, isDisableSearchComponent, isFullscreenOnMobile, props.preventScroll]);
  var handleClickListItem = function handleClickListItem(option) {
    return function (e) {
      e.preventDefault();
      send({
        type: 'ITEM_CLICK',
        payload: option
      });
      return false;
    };
  };
  var handleClickActionItem = function handleClickActionItem(action) {
    return function (e) {
      e.preventDefault();
      send({
        type: 'SELECT_ITEM',
        payload: action
      });
      return false;
    };
  };
  var handleKeyDown = useDelegateKeyDownToMachine(send, !props.showSearch);
  var isKeyboardNavigation = machineState.matches('interaction.enabled.active.navigation.keyboard');
  var handleMouseMove = useCallback(function () {
    if (isKeyboardNavigation) {
      send('MOUSE_MOVE');
    }
  }, [send, isKeyboardNavigation]);
  var buttonRef = useRef(null);
  var _useMultiRef = useMultiRef(),
    _useMultiRef2 = _slicedToArray(_useMultiRef, 2),
    itemRefs = _useMultiRef2[0],
    setItemRef = _useMultiRef2[1];
  var listRef = useRef(null);
  var formFieldRef = useRef(null);
  var selectWrapperRef = useRef(null);
  var inputRef = useRef(null);
  var searchRef = useRef(null);
  useAutofocus(buttonRef, props.autoFocus);
  useFocusFromMachine(machineState, buttonRef, itemRefs, searchRef, props.preventScroll);
  var _useOnBlurAndOnFocus = useOnBlurAndOnFocus(machineState, send, props.onBlur, props.onFocus, formFieldRef, isFirstRender, inputRef, listRef),
    handleBlur = _useOnBlurAndOnFocus.handleBlur,
    handleFocus = _useOnBlurAndOnFocus.handleFocus;
  var _useComponentsWithDef = useComponentsWithDefaults(props.components, {
      multiselect: machineState.context.multiselect
    }),
    ListItem = _useComponentsWithDef.ListItem,
    List = _useComponentsWithDef.List,
    ListFullScreen = _useComponentsWithDef.ListFullScreen,
    SelectedValue = _useComponentsWithDef.SelectedValue,
    Search = _useComponentsWithDef.Search,
    Action = _useComponentsWithDef.Action;
  var isOpen = machineState.context.open;
  var isDisabled = machineState.context.disabled;
  var error = machineState.context.error;
  var success = machineState.context.success;
  var extraInfo = machineState.context.extraInfo;
  var label = machineState.context.label;
  var placeholder = machineState.context.placeholder;
  var options = machineState.context.visibleOptions;
  var selectedItems = machineState.context.selectedItems;
  var multiselect = machineState.context.multiselect;
  var disableSearchComponent = machineState.context.disableSearchComponent;
  var isFullScreenMode = machineState.context.fullscreenOnMobile;
  var ListWrapperComponent = props.withPortal ? ListWrapperWithPortal : ListWrapper;
  var hiddenSelectValues = getValuesForNativeSelect(selectedItems, multiselect);
  useOnClickOutside([listRef, formFieldRef], function () {
    if (!isFullScreenMode) send({
      type: 'BLUR'
    });
  });
  var onClose = useCallback(function () {
    send({
      type: 'CLOSE'
    });
  }, [send]);
  return React.createElement("div", {
    className: props.className
  }, React.createElement(HiddenSelect, _extends({
    name: props.name,
    disabled: isDisabled,
    ref: inputRef,
    "aria-hidden": "true"
  }, multiselect ? {
    multiple: true
  } : {}, {
    value: hiddenSelectValues,
    onChange: noop
  }), placeholder && React.createElement("option", {
    label: placeholder,
    value: ""
  }), options === null || options === void 0 ? void 0 : options.map(function (x) {
    var _x$options;
    return x.options ? React.createElement("optgroup", {
      label: x.label,
      key: x.label
    }, (_x$options = x.options) === null || _x$options === void 0 ? void 0 : _x$options.map(function (y) {
      return React.createElement("option", {
        label: y.label,
        value: y.value,
        key: "".concat(y.label).concat(y.value)
      });
    })) : React.createElement("option", {
      label: x.label,
      value: x.value,
      key: "".concat(x.label).concat(x.value)
    });
  })), React.createElement(SelectStateContext.Provider, {
    value: machineHandlers
  }, React.createElement(FormFieldOrFragment, {
    label: label,
    hideLabel: props.hideLabel,
    labelToolTip: props.labelTooltip,
    labelTooltipPosition: props.labelTooltipPosition,
    labelTooltipInModal: props.labelTooltipInModal,
    noFormField: props.noFormField,
    ref: formFieldRef,
    innerRef: selectWrapperRef,
    disabled: isDisabled,
    open: isOpen,
    fullWidth: props.fullWidth,
    error: error,
    success: success,
    extraInfo: extraInfo,
    height: props.height,
    id: props.id,
    size: props.size,
    onFocus: handleFocus,
    onBlur: !isFullScreenMode ? handleBlur : undefined,
    width: props.width
  }, React.createElement(SelectedValueWrapper, {
    ref: buttonRef,
    open: isOpen,
    label: label,
    disabled: isDisabled,
    noFormField: props.noFormField,
    placeholder: placeholder,
    component: SelectedValue,
    options: options,
    state: machineState,
    id: props.id
  }), isOpen && !isFullScreenMode && React.createElement(ListWrapperComponent, {
    component: List,
    itemsPerColumn: props.itemsPerColumn,
    columnWidth: props.columnWidth,
    triggerElement: selectWrapperRef,
    noFormField: props.noFormField,
    onKeyDown: handleKeyDown,
    onMouseMove: handleMouseMove,
    ref: listRef,
    searchComponent: !disableSearchComponent && React.createElement(SearchWrapper, {
      ref: searchRef,
      component: Search
    }),
    listPosition: props.listPosition,
    listWidth: props.listWidth,
    placement: props.placement,
    invertedColors: props.invertedColors,
    actionsComponent: machineState.context.actions.length > 0 ? React.createElement(ActionsWrapper, {
      component: Action,
      onClickFactory: handleClickActionItem
    }) : null,
    maxHeight: props.listMaxHeight,
    width: props.listWidth || props.width
  }, options === null || options === void 0 ? void 0 : options.filter(function (x) {
    return !(props.hideDisabledOptions && x.disabled);
  }).map(function (x, index) {
    return React.createElement(ListItemWrapper, {
      key: index,
      index: index,
      ref: setItemRef(index),
      option: x,
      id: props.id,
      onClick: x.disabled || x.options ? noop : handleClickListItem(x),
      component: ListItem
    });
  })), isOpen && isFullScreenMode && React.createElement(Modal, {
    open: isOpen,
    title: React.createElement(Typography, {
      type: "title1",
      weight: "bold"
    }, props.label),
    onClose: onClose
  }, React.createElement(ListWrapperComponent, {
    component: ListFullScreen,
    triggerElement: selectWrapperRef,
    noFormField: props.noFormField,
    onKeyDown: handleKeyDown,
    onMouseMove: handleMouseMove,
    ref: listRef,
    searchComponent: !disableSearchComponent && React.createElement(SearchWrapper, {
      ref: searchRef,
      component: Search
    }),
    listPosition: props.listPosition,
    listWidth: props.listWidth,
    placement: "top",
    invertedColors: props.invertedColors,
    actionsComponent: machineState.context.actions.length > 0 ? React.createElement(ActionsWrapper, {
      component: Action,
      onClickFactory: handleClickActionItem
    }) : null,
    maxHeight: props.listMaxHeight
  }, options === null || options === void 0 ? void 0 : options.filter(function (x) {
    return !(props.hideDisabledOptions && x.disabled);
  }).map(function (x, index) {
    return React.createElement(ListItemWrapper, {
      key: index,
      index: index,
      ref: setItemRef(index),
      option: x,
      id: props.id,
      onClick: x.disabled || x.options ? noop : handleClickListItem(x),
      component: ListItem
    });
  }))))));
};
Select.useSelectMachineFromContext = useSelectMachineFromContext;
Select.ACTION_TYPES = ACTION_TYPES;
Select.SYMBOL_ALL = SYMBOL_ALL;
Select.defaults = {
  components: defaultComponents,
  componentsMultiselect: defaultComponentsMultiselect
};
export { Select };