import { isNumber, isEmpty, isNull } from '@transferwise/neptune-validation';
import { Flag } from '@wise/art';
import { clsx } from 'clsx';
import { Component } from 'react';
import { injectIntl } from 'react-intl';
import '../common/theme.mjs';
import '../common/direction.mjs';
import '../common/propsValues/control.mjs';
import '../common/propsValues/breakpoint.mjs';
import { Size } from '../common/propsValues/size.mjs';
import { Typography } from '../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 '../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 { withInputAttributes } from '../inputs/contexts.mjs';
import { Input } from '../inputs/Input.mjs';
import { SelectInput, SelectInputOptionContent } from '../inputs/SelectInput.mjs';
import Title from '../title/Title.mjs';
import messages from './MoneyInput.messages.mjs';
import { parseAmount } from './currencyFormatting.mjs';
import withId from '../withId/withId.mjs';
import { formatAmount } from '@transferwise/formatting';

const isNumberOrNull = v => isNumber(v) || isNull(v);
const formatAmountIfSet = ({
  amount,
  currency,
  locale
}) => {
  return typeof amount === 'number' ? formatAmount(amount, currency, locale) : '';
};
const parseNumber = ({
  amount,
  currency,
  locale
}) => {
  return parseAmount(amount, currency, locale);
};
const allowedInputKeys = new Set(['Backspace', 'Delete', ',', '.', 'ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Enter', 'Escape', 'Tab']);
class MoneyInput extends Component {
  static defaultProps = {
    size: Size.LARGE,
    classNames: {},
    selectProps: {}
  };
  amountFocused = false;
  constructor(props) {
    super(props);
    this.state = {
      searchQuery: '',
      formattedAmount: formatAmountIfSet({
        amount: props.amount,
        currency: props.selectedCurrency.currency,
        locale: props.intl.locale
      }),
      locale: props.intl.locale
    };
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    this.setState({
      locale: nextProps.intl.locale
    });
    if (!this.amountFocused) {
      this.setState({
        formattedAmount: formatAmountIfSet({
          amount: nextProps.amount,
          currency: nextProps.selectedCurrency.currency,
          locale: nextProps.intl.locale
        })
      });
    }
  }
  isInputAllowedForKeyEvent = event => {
    const {
      metaKey,
      key,
      ctrlKey
    } = event;
    const isNumberKey = isNumber(Number.parseInt(key, 10));
    return isNumberKey || metaKey || ctrlKey || allowedInputKeys.has(key);
  };
  handleKeyDown = event => {
    if (!this.isInputAllowedForKeyEvent(event)) {
      event.preventDefault();
    }
  };
  handlePaste = event => {
    const paste = event.clipboardData.getData('text');
    const {
      locale
    } = this.state;
    const parsed = isEmpty(paste) ? null : parseNumber({
      amount: paste,
      currency: this.props.selectedCurrency.currency,
      locale
    });
    if (isNumberOrNull(parsed)) {
      this.setState({
        formattedAmount: formatAmountIfSet({
          amount: parsed,
          currency: this.props.selectedCurrency.currency,
          locale
        })
      });
      this.props.onAmountChange?.(parsed);
    }
    event.preventDefault();
  };
  onAmountChange = event => {
    const {
      value
    } = event.target;
    this.setState({
      formattedAmount: value
    });
    const parsed = isEmpty(value) ? null : parseNumber({
      amount: value,
      currency: this.props.selectedCurrency.currency,
      locale: this.state.locale
    });
    if (isNumberOrNull(parsed)) {
      this.props.onAmountChange?.(parsed);
    }
  };
  onAmountBlur = () => {
    this.amountFocused = false;
    this.setAmount();
  };
  onAmountFocus = () => {
    this.amountFocused = true;
  };
  getSelectOptions() {
    const selectOptions = filterCurrenciesForQuery(this.props.currencies, this.state.searchQuery);
    const formattedOptions = [];
    let currentGroupOptions;
    selectOptions.forEach(item => {
      if (item.header != null) {
        currentGroupOptions = [];
        formattedOptions.push({
          type: 'group',
          label: item.header,
          options: currentGroupOptions
        });
      } else {
        (currentGroupOptions ?? formattedOptions).push({
          type: 'option',
          value: item,
          filterMatchers: [item.value, item.label, item.note ?? '', item.searchable ?? '']
        });
      }
    });
    return formattedOptions;
  }
  setAmount() {
    this.setState(previousState => {
      const parsed = parseNumber({
        amount: previousState.formattedAmount,
        currency: this.props.selectedCurrency.currency,
        locale: previousState.locale
      });
      if (!isNumberOrNull(parsed)) {
        return {
          formattedAmount: previousState.formattedAmount
        };
      }
      return {
        formattedAmount: formatAmountIfSet({
          amount: parsed,
          currency: this.props.selectedCurrency.currency,
          locale: previousState.locale
        })
      };
    });
  }
  handleSelectChange = value => {
    this.handleSearchChange('');
    this.props.onCurrencyChange?.(value);
  };
  handleCustomAction = () => {
    this.handleSearchChange('');
    this.props.onCustomAction?.();
  };
  handleSearchChange = searchQuery => {
    this.setState({
      searchQuery
    });
    this.props.onSearchChange?.({
      searchQuery,
      filteredOptions: filterCurrenciesForQuery(this.props.currencies, searchQuery)
    });
  };
  style = className => this.props.classNames[className] || className;
  render() {
    const {
      inputAttributes,
      id: amountInputId,
      'aria-labelledby': ariaLabelledByProp,
      selectedCurrency,
      onCurrencyChange,
      size,
      addon,
      selectProps
    } = this.props;
    const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes?.['aria-labelledby'];
    const selectOptions = this.getSelectOptions();
    const hasSingleCurrency = () => {
      if (selectOptions.length !== 0) {
        const firstItem = selectOptions[0];
        if (selectOptions.length === 1) {
          if (firstItem.type === 'option') {
            return firstItem.value.currency === selectedCurrency.currency;
          }
          if (firstItem.type === 'group') {
            return firstItem.options.length === 1 && !(this.props.onCustomAction && this.props.customActionLabel);
          }
        }
      } else if (selectedCurrency?.currency) {
        return true;
      }
      return false;
    };
    const isFixedCurrency = !this.state.searchQuery && hasSingleCurrency() || !onCurrencyChange;
    const disabled = !this.props.onAmountChange;
    const selectedCurrencyElementId = `${inputAttributes?.id ?? amountInputId}SelectedCurrency`;
    return /*#__PURE__*/jsxs("div", {
      role: "group",
      ...inputAttributes,
      "aria-labelledby": ariaLabelledBy,
      className: clsx(this.style('tw-money-input'), this.style('input-group'), this.style(`input-group-${size}`)),
      children: [/*#__PURE__*/jsx(Input, {
        id: amountInputId,
        value: this.state.formattedAmount,
        inputMode: "decimal",
        disabled: disabled,
        placeholder: formatAmountIfSet({
          amount: this.props.placeholder,
          currency: this.props.selectedCurrency.currency,
          locale: this.state.locale
        }),
        autoComplete: "off",
        "aria-describedby": selectedCurrencyElementId,
        onKeyDown: this.handleKeyDown,
        onChange: this.onAmountChange,
        onFocus: this.onAmountFocus,
        onBlur: this.onAmountBlur,
        onPaste: this.handlePaste
      }), addon && /*#__PURE__*/jsx("span", {
        className: clsx(this.style('input-group-addon'), this.style(`input-${size}`), disabled ? this.style('disabled') : ''),
        children: addon
      }), isFixedCurrency ? /*#__PURE__*/jsxs("div", {
        className: clsx(this.style('input-group-addon'), this.style(`input-${size}`), this.style('tw-money-input__fixed-currency'), disabled ? this.style('disabled') : ''),
        id: selectedCurrencyElementId,
        children: [(size === 'lg' || size === 'md') && /*#__PURE__*/jsx("span", {
          className: clsx(this.style('money-input-currency-flag'), this.style('m-r-2')),
          children: /*#__PURE__*/jsx(Flag, {
            code: selectedCurrency.currency.toLowerCase(),
            intrinsicSize: 24
          })
        }), /*#__PURE__*/jsx(Title, {
          as: "span",
          type: Typography.TITLE_SUBSECTION,
          className: size === 'lg' ? this.style('m-r-1') : '',
          children: selectedCurrency.currency.toUpperCase()
        })]
      }) : /*#__PURE__*/jsx("div", {
        translate: "no",
        className: clsx(this.style('input-group-btn'), this.style('amount-currency-select-btn')),
        children: /*#__PURE__*/jsx(SelectInput, {
          UNSAFE_triggerButtonProps: {
            id: undefined,
            'aria-labelledby': undefined,
            'aria-describedby': ariaLabelledBy,
            'aria-invalid': undefined,
            'aria-label': this.props.intl.formatMessage(messages.selectCurrencyLabel)
          },
          id: selectedCurrencyElementId,
          items: selectOptions,
          value: selectedCurrency,
          compareValues: "currency",
          renderValue: (currency, withinTrigger) => {
            return /*#__PURE__*/jsx(SelectInputOptionContent, {
              title: withinTrigger ? currency.currency.toUpperCase() : currency.label,
              note: withinTrigger ? undefined : currency.note,
              icon: /*#__PURE__*/jsx(Flag, {
                code: currency.currency,
                intrinsicSize: 24
              })
            });
          },
          renderFooter: this.props.onCustomAction ? () =>
          /*#__PURE__*/
          // eslint-disable-next-line jsx-a11y/click-events-have-key-events
          jsx("div", {
            role: "button",
            tabIndex: 0,
            onClick: this.handleCustomAction,
            children: this.props.customActionLabel
          }) : undefined,
          placeholder: this.props.intl.formatMessage(messages.selectPlaceholder),
          filterable: true,
          filterPlaceholder: this.props.searchPlaceholder,
          disabled: disabled,
          size: size,
          onChange: this.handleSelectChange,
          onFilterChange: ({
            queryNormalized
          }) => {
            this.handleSearchChange(queryNormalized ?? '');
          },
          ...selectProps
        })
      })]
    });
  }
}
function filterCurrenciesForQuery(currencies, query) {
  if (!query) {
    return [...currencies];
  }
  const options = currencies.filter(option => option.header == null);
  const filteredOptions = removeDuplicateValueOptions(options).filter(option => currencyOptionFitsQuery(option, query));
  return sortOptionsLabelsToFirst(filteredOptions, query);
}
function removeDuplicateValueOptions(options) {
  const uniqueValues = new Set();
  return options.filter(option => {
    if (!uniqueValues.has(option.value)) {
      uniqueValues.add(option.value);
      return true;
    }
    return false;
  });
}
function currencyOptionFitsQuery(option, query) {
  if (!option.value) {
    return false;
  }
  return contains(option.label, query) || contains(option.searchable, query) || contains(option.note, query);
}
function contains(property, query) {
  return property?.toLowerCase().includes(query.toLowerCase());
}
function sortOptionsLabelsToFirst(options, query) {
  return [...options].sort((first, second) => {
    const firstContains = contains(first.label, query);
    const secondContains = contains(second.label, query);
    if (firstContains && secondContains) {
      return 0;
    }
    if (firstContains) {
      return -1;
    }
    if (secondContains) {
      return 1;
    }
    return 0;
  });
}
var MoneyInput$1 = injectIntl(withId(withInputAttributes(MoneyInput, {
  nonLabelable: true
})));

export { MoneyInput$1 as default };
//# sourceMappingURL=MoneyInput.mjs.map
