import { clsx } from 'clsx';
import { useState, useRef, useMemo, useId, useEffect } from 'react';
import { useIntl } from 'react-intl';
import Button from '../button/Button.resolver.mjs';
import Chevron from '../chevron/Chevron.mjs';
import { stopPropagation } from '../common/domHelpers/documentIosClick.mjs';
import '../common/theme.mjs';
import '../common/direction.mjs';
import '../common/propsValues/control.mjs';
import '../common/propsValues/breakpoint.mjs';
import '../common/propsValues/size.mjs';
import '../common/propsValues/typography.mjs';
import '../common/propsValues/width.mjs';
import '../common/propsValues/type.mjs';
import '../common/propsValues/dateMode.mjs';
import '../common/propsValues/monthFormat.mjs';
import { Position } from '../common/propsValues/position.mjs';
import '../common/propsValues/layouts.mjs';
import '../common/propsValues/status.mjs';
import '../common/propsValues/sentiment.mjs';
import '../common/propsValues/profileType.mjs';
import '../common/propsValues/variant.mjs';
import '../common/propsValues/scroll.mjs';
import '../common/propsValues/markdownNodeType.mjs';
import '../common/fileType.mjs';
import '@transferwise/icons';
import '../common/closeButton/CloseButton.messages.mjs';
import { jsxs, jsx } from 'react/jsx-runtime';
import BottomSheet from '../common/bottomSheet/BottomSheet.mjs';
import '@transferwise/neptune-validation';
import '../provider/direction/DirectionProvider.mjs';
import { useLayout } from '../common/hooks/useLayout/useLayout.mjs';
import Panel from '../common/panel/Panel.mjs';
import Drawer from '../drawer/Drawer.mjs';
import { useInputAttributes } from '../inputs/contexts.mjs';
import messages from './Select.messages.mjs';
import Option from './option/Option.mjs';
import SearchBox from './searchBox/SearchBox.mjs';

const DEFAULT_SEARCH_VALUE = '';
const DEFAULT_OPTIONS_PAGE_SIZE = 1000;
const includesString = (string1, string2) => string1.toLowerCase().includes(string2.toLowerCase());
function defaultFilterFunction(option, searchValue) {
  if (isPlaceholderOption(option)) {
    return true;
  }
  const {
    label,
    note,
    secondary,
    currency,
    searchStrings
  } = option;
  return typeof label === 'string' && includesString(label, searchValue) || typeof note === 'string' && includesString(note, searchValue) || typeof secondary === 'string' && includesString(secondary, searchValue) || !!currency && includesString(currency, searchValue) || !!searchStrings && searchStrings.some(string => includesString(string, searchValue));
}
function isActionableOption(option) {
  return !option.header && !option.separator && !option.disabled;
}
function isHeaderOption(option) {
  return option != null && 'header' in option;
}
function isSeparatorOption(option) {
  return option != null && 'separator' in option;
}
function clamp(from, to, value) {
  return Math.max(Math.min(to, value), from);
}
/**
 * No option or placeholder option is selected
 */
const DEFAULT_SELECTED_OPTION = null;
function isPlaceholderOption(option) {
  return option === DEFAULT_SELECTED_OPTION || 'placeholder' in option;
}
function isSearchableOption(option) {
  return !isHeaderOption(option) && !isSeparatorOption(option) && !isPlaceholderOption(option);
}
const getUniqueIdForOption = (parentId, option) => {
  if (option == null) {
    return undefined;
  }
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  const uniqueOptionId = option.value || (typeof option.label === 'string' ? option.label.replace(/\s/g, '') : '');
  return `option-${parentId ?? ''}-${uniqueOptionId}`;
};
const defaultClassNames = {};
/**
 * @deprecated Use `SelectInput` instead (https://neptune.wise.design/blog/2023-11-28-adopting-our-new-selectinput)
 */
function Select({
  placeholder,
  id,
  required,
  disabled,
  inverse,
  dropdownWidth,
  size = 'md',
  block = true,
  selected,
  search,
  onChange,
  onFocus,
  onBlur,
  options: defaultOptions,
  onSearchChange,
  searchValue: initSearchValue = '',
  searchPlaceholder,
  classNames: classNamesProp = defaultClassNames,
  dropdownUp,
  dropdownProps,
  buttonProps
}) {
  const inputAttributes = useInputAttributes();
  const {
    formatMessage
  } = useIntl();
  const s = className => classNamesProp[className] || className;
  const [open, setOpen] = useState(false);
  const [searchValue, setSearchValue] = useState(DEFAULT_SEARCH_VALUE);
  const [keyboardFocusedOptionIndex, setKeyboardFocusedOptionIndex] = useState(-1);
  const keyboardFocusedReference = useRef(null);
  const previousKeyboardFocusedOptionIndex = useRef(-1);
  const [numberOfOptionsShown, setNumberOfOptionsShown] = useState(DEFAULT_OPTIONS_PAGE_SIZE);
  const searchBoxReference = useRef(null);
  const selectReference = useRef(null);
  const dropdownButtonReference = useRef(null);
  const optionsListReference = useRef(null);
  const isSearchEnabled = !!onSearchChange || !!search;
  const isDropdownAutoWidth = dropdownWidth == null;
  const options = useMemo(() => {
    if (!search || !searchValue) {
      return defaultOptions;
    }
    return defaultOptions.filter(isSearchableOption).filter(option => {
      if (typeof search === 'function') {
        return search(option, searchValue);
      }
      return defaultFilterFunction(option, searchValue);
    });
  }, [defaultOptions, search, searchValue]);
  const selectableOptions = useMemo(() => options.filter(isActionableOption), [options]);
  const focusedOption = selectableOptions[keyboardFocusedOptionIndex];
  const fallbackButtonId = useId();
  const computedId = id || inputAttributes.id || fallbackButtonId;
  const listboxId = `${computedId}-listbox`;
  const searchBoxId = `${computedId}-searchbox`;
  const {
    isMobile
  } = useLayout();
  useEffect(() => {
    let cancelled = false;
    if (keyboardFocusedOptionIndex >= 0) {
      requestAnimationFrame(() => {
        if (!cancelled) {
          if (isSearchEnabled) {
            keyboardFocusedReference.current?.scrollIntoView?.({
              block: 'center'
            });
          } else {
            keyboardFocusedReference.current?.focus();
          }
        }
      });
      return () => {
        cancelled = true;
      };
    }
  }, [keyboardFocusedOptionIndex, isSearchEnabled]);
  const handleOnClick = () => {
    setOpen(true);
  };
  const handleTouchStart = event => {
    if (event.currentTarget === event.target && open) {
      handleCloseOptions();
    }
  };
  const handleOnFocus = event => {
    onFocus?.(event);
  };
  const handleOnBlur = event => {
    const {
      nativeEvent
    } = event;
    if (nativeEvent) {
      const elementReceivingFocus = nativeEvent.relatedTarget;
      const select = event.currentTarget;
      if (select && elementReceivingFocus instanceof Node && select.contains(elementReceivingFocus)) {
        return;
      }
    }
    onBlur?.(event);
  };
  const handleSearchChange = event => {
    setNumberOfOptionsShown(DEFAULT_OPTIONS_PAGE_SIZE);
    setSearchValue(event.target.value);
    onSearchChange?.(event.target.value);
  };
  const handleKeyDown = event => {
    switch (event.key) {
      case 'ArrowUp':
      case 'ArrowDown':
        if (open) {
          moveFocusWithDifference(event.key === 'ArrowUp' ? -1 : 1);
        } else {
          setOpen(true);
        }
        stopPropagation(event);
        break;
      case ' ':
        if (event.target !== searchBoxReference.current) {
          if (open) {
            selectKeyboardFocusedOption();
          } else {
            setOpen(true);
          }
          stopPropagation(event);
        }
        break;
      case 'Enter':
        if (open) {
          selectKeyboardFocusedOption();
        } else {
          setOpen(true);
        }
        stopPropagation(event);
        break;
      case 'Escape':
        handleCloseOptions();
        stopPropagation(event);
        break;
      case 'Tab':
        if (open) {
          selectKeyboardFocusedOption();
        }
        break;
    }
  };
  function selectKeyboardFocusedOption() {
    if (keyboardFocusedOptionIndex >= 0 && selectableOptions.length > 0) {
      selectOption(selectableOptions[keyboardFocusedOptionIndex]);
    }
  }
  function moveFocusWithDifference(difference) {
    const selectedOptionIndex = selectableOptions.reduce((optionIndex, current, index) => {
      if (optionIndex >= 0) {
        return optionIndex;
      }
      if (isOptionSelected(selected, current)) {
        return index;
      }
      return -1;
    }, -1);
    const previousFocusedIndex = previousKeyboardFocusedOptionIndex.current;
    let indexToStartMovingFrom = previousFocusedIndex;
    if (previousFocusedIndex < 0) {
      if (selectedOptionIndex < 0) {
        setKeyboardFocusedOptionIndex(0);
      } else {
        indexToStartMovingFrom = selectedOptionIndex;
      }
    }
    const unClampedNewIndex = indexToStartMovingFrom + difference;
    const newIndex = clamp(0, selectableOptions.length - 1, unClampedNewIndex);
    setKeyboardFocusedOptionIndex(newIndex);
  }
  useEffect(() => {
    if (open) {
      if (!isMobile || searchValue) {
        if (isSearchEnabled && searchBoxReference.current) {
          searchBoxReference.current.focus();
        }
        if (!isSearchEnabled && optionsListReference.current && previousKeyboardFocusedOptionIndex.current < 0) {
          optionsListReference.current.focus();
        }
      }
      previousKeyboardFocusedOptionIndex.current = keyboardFocusedOptionIndex;
    } else {
      previousKeyboardFocusedOptionIndex.current = -1;
    }
  }, [open, searchValue, isSearchEnabled, isMobile, keyboardFocusedOptionIndex]);
  const handleCloseOptions = () => {
    setOpen(false);
    setKeyboardFocusedOptionIndex(-1);
    if (dropdownButtonReference.current) {
      dropdownButtonReference.current.focus();
    }
  };
  function createSelectHandlerForOption(option) {
    return event => {
      stopPropagation(event);
      selectOption(option);
    };
  }
  function selectOption(option) {
    onChange(isPlaceholderOption(option) ? DEFAULT_SELECTED_OPTION : option);
    handleCloseOptions();
  }
  function renderOptionsList({
    className = ''
  } = {}) {
    const dropdownClass = clsx(s('np-dropdown-menu'), {
      [s('np-dropdown-menu-desktop')]: !isMobile,
      [s(`np-dropdown-menu-${dropdownWidth}`)]: !isMobile && !isDropdownAutoWidth
    }, s(className));
    const showPlaceholder = !required && !isSearchEnabled && Boolean(placeholder);
    return /*#__PURE__*/jsxs("ul", {
      ref: optionsListReference,
      id: listboxId,
      role: "listbox",
      "aria-orientation": "vertical",
      "aria-activedescendant": getUniqueIdForOption(id, selected ?? null),
      tabIndex: -1,
      className: dropdownClass,
      ...dropdownProps,
      children: [showPlaceholder && /*#__PURE__*/jsx(PlaceHolderOption, {}), isSearchEnabled && /*#__PURE__*/jsx(SearchBox, {
        ref: searchBoxReference,
        id: searchBoxId,
        classNames: classNamesProp,
        value: initSearchValue || searchValue,
        placeholder: searchPlaceholder || formatMessage(messages.searchPlaceholder),
        focusedOptionId: getUniqueIdForOption(id, focusedOption),
        onChange: handleSearchChange,
        onClick: stopPropagation
      }), options.slice(0, numberOfOptionsShown).map(renderOption), numberOfOptionsShown < options.length && /*#__PURE__*/jsx(ShowMoreOption, {})]
    });
  }
  function ShowMoreOption() {
    function handleOnClick(event) {
      stopPropagation(event);
      setNumberOfOptionsShown(numberOfOptionsShown + DEFAULT_OPTIONS_PAGE_SIZE);
    }
    return /*#__PURE__*/ /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */jsx("li", {
      className: clsx(s('clickable'), s('border-bottom'), s('show-more')),
      onClick: handleOnClick,
      onKeyPress: handleOnClick,
      children: /*#__PURE__*/jsx("a", {
        children: "..."
      })
    });
  }
  function PlaceHolderOption() {
    const placeholderOption = {
      placeholder
    };
    return /*#__PURE__*/ /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */jsx("li", {
      className: clsx(s('clickable'), s('border-bottom')),
      onClick: createSelectHandlerForOption(placeholderOption),
      onKeyPress: createSelectHandlerForOption(placeholderOption),
      children: /*#__PURE__*/jsx("a", {
        children: placeholder
      })
    });
  }
  function SeparatorOption() {
    return /*#__PURE__*/jsx("li", {
      className: s('np-separator'),
      "aria-hidden": true
    });
  }
  function HeaderOption({
    children
  }) {
    return /*#__PURE__*/jsx("li", {
      // eslint-disable-line jsx-a11y/no-noninteractive-element-interactions
      className: clsx(s('np-dropdown-header'), s('np-text-title-group')),
      onClick: stopPropagation,
      onKeyPress: stopPropagation,
      children: children
    });
  }
  function isOptionSelected(selected, option) {
    return selected?.value === option?.value;
  }
  const renderOption = (option, index) => {
    const separatorOption = option;
    if (isSeparatorOption(separatorOption) && separatorOption?.separator) {
      return /*#__PURE__*/jsx(SeparatorOption, {}, index);
    }
    const headerOption = option;
    if (isHeaderOption(headerOption) && headerOption.header) {
      return /*#__PURE__*/jsx(HeaderOption, {
        children: headerOption.header
      }, index);
    }
    const isActive = isOptionSelected(selected, option);
    const selectOption = option;
    const isFocusedWithKeyboard = !selectOption.disabled && keyboardFocusedOptionIndex === getIndexWithoutHeadersForIndexWithHeaders(index);
    const className = clsx(s('np-dropdown-item'), selectOption.disabled ? [s('disabled')] : s('clickable'), {
      [s('active')]: isActive,
      [s('np-dropdown-item--focused')]: isFocusedWithKeyboard
    });
    const handleOnClick = selectOption.disabled ? stopPropagation : createSelectHandlerForOption(selectOption);
    return /*#__PURE__*/jsx("li", {
      ref: isFocusedWithKeyboard ? keyboardFocusedReference : undefined,
      id: getUniqueIdForOption(id, option),
      "aria-selected": isActive,
      "aria-disabled": option.disabled,
      role: "option",
      tabIndex: -1,
      className: className,
      onClick: handleOnClick,
      onKeyPress: handleOnClick,
      children: /*#__PURE__*/jsx("a", {
        disabled: selectOption.disabled,
        children: /*#__PURE__*/jsx(Option, {
          label: undefined,
          value: undefined,
          ...selectOption,
          classNames: classNamesProp
        })
      })
    }, index);
  };
  function getIndexWithoutHeadersForIndexWithHeaders(index) {
    return options.reduce((sum, option, currentIndex) => {
      if (currentIndex < index && isActionableOption(option)) {
        return sum + 1;
      }
      return sum;
    }, 0);
  }
  const hasActiveOptions = !!defaultOptions.length;
  if (open && (initSearchValue || searchValue)) {
    if (hasActiveOptions && keyboardFocusedOptionIndex < 0) {
      setKeyboardFocusedOptionIndex(0);
    }
    if (!hasActiveOptions && keyboardFocusedOptionIndex >= 0) {
      setKeyboardFocusedOptionIndex(-1);
    }
  }
  return /*#__PURE__*/jsxs("div", {
    // eslint-disable-line jsx-a11y/no-static-element-interactions
    ref: selectReference,
    className: clsx(s('np-select'), block ? s('btn-block') : null, s('btn-group')),
    onKeyDown: handleKeyDown,
    onTouchMove: handleTouchStart,
    onFocus: handleOnFocus,
    onBlur: handleOnBlur,
    children: [/*#__PURE__*/jsxs(Button, {
      ref: dropdownButtonReference,
      ...inputAttributes,
      id: computedId,
      block: block,
      size: size,
      htmlType: "button",
      className: clsx(s('np-dropdown-toggle'), s('np-text-body-large'), inverse ? s('np-dropdown-toggle-navy') : null)
      // reset Button's styles
      ,
      type: null,
      priority: null,
      disabled: disabled,
      "aria-controls": listboxId,
      "aria-expanded": open,
      onClick: handleOnClick,
      ...buttonProps,
      children: [selected ? /*#__PURE__*/jsx(Option, {
        label: undefined,
        ...selected,
        classNames: classNamesProp,
        selected: true
      }) : /*#__PURE__*/jsx("span", {
        className: s('form-control-placeholder'),
        children: placeholder
      }), /*#__PURE__*/jsx(Chevron
      // disabled={disabled}
      , {
        className: clsx(s('tw-icon'), s('tw-chevron-up-icon'), s('tw-chevron'), s('bottom'), s('np-select-chevron'))
      })]
    }), isMobile ? isSearchEnabled ? /*#__PURE__*/jsx(Drawer, {
      open: open,
      headerTitle: searchPlaceholder || formatMessage(messages.searchPlaceholder),
      onClose: handleCloseOptions,
      children: renderOptionsList()
    }) : /*#__PURE__*/jsx(BottomSheet, {
      open: open,
      onClose: handleCloseOptions,
      children: renderOptionsList()
    }) : /*#__PURE__*/jsx(Panel, {
      open: open,
      flip: false,
      altAxis: true,
      anchorRef: selectReference,
      anchorWidth: isDropdownAutoWidth,
      position: dropdownUp ? Position.TOP : Position.BOTTOM,
      onClose: handleCloseOptions,
      children: renderOptionsList({
        className: 'p-a-1'
      })
    })]
  });
}

export { Select as default };
//# sourceMappingURL=Select.mjs.map
