// @flow
import type { Node } from 'react';
import type { TranslatedContent } from '../../../types';
import type { SpaceProps } from '../../../mixins/spacing';
import type { StackeeProps } from '../../../mixins/stackee';
import type { StylableProps } from '../../../mixins/themes';
import type { TestingProps } from '../../../mixins/testing';
import type { AriaProps } from '../../../mixins/aria';
import type { FocusEvents } from '../../../mixins/focus';
import type { FontSize } from '../../../mixins/typography';
import type { FormFieldError } from '../internals/forms.proptypes';

// This is from CleaveJS. See https://github.com/nosir/cleave.js/blob/master/doc/options.md
// for details.
export type MaskedTextInputOptions = {|
  blocks?: number[],
  date?: boolean,
  dateMax?: string,
  dateMin?: string,
  datePattern?: Array<string>,
  delimiter?: string,
  noImmediatePrefix?: boolean,
  numeral?: boolean,
  numeralDecimalMark?: string,
  numeralDecimalScale?: number,
  numericOnly?: boolean,
  phone?: boolean,
  phoneRegionCode?: string,
  prefix?: string,
  rawValueTrimPrefix?: boolean,
  uppercase?: boolean,
|};

export type CurrencyCode = 'CAD' | 'USD' | 'GBP';

export type TextInputType =
  | 'date'
  | 'email'
  | 'number'
  | 'text'
  | 'password'
  | 'currency'
  | 'grouped_code'
  | 'search'
  | 'custom';

export type LabelStyle =
  /* default */
  | 'floating'

  /* Legacy designs & special cases */
  | 'external'
  | 'external-large'

  /* Deprecated: it's not WCAG compliant to have a label that disappears. */
  | 'hidden';

export type TextInputProps<ValueType> = {|
  ...TestingProps,
  ...StylableProps,
  ...SpaceProps,
  ...StackeeProps,
  ...AriaProps,
  ...FocusEvents,
  autocomplete?: string,
  disabled?: boolean,
  readOnly?: boolean,
  locked?: boolean,
  focusOnMount?: boolean,
  fontSize?: FontSize,
  inputMode?: string,
  label: TranslatedContent,
  name?: string,
  placeholder?: string,
  type?: TextInputType,
  labelStyle?: LabelStyle,

  // Render the control in a way suitable for embedding inside another component
  // e.g. a free-form ListSelector element.
  isEmbeddable?: boolean,

  // Cleave's ref handling needs to be updated. See https://github.com/nosir/cleave.js/issues/497
  // For now we need to work around it with a custom callback prop instead of using
  // forwardRef. TODO: it bugs me that this detail of CleaveJS is leaking into our
  // exported interface.
  onRef?: (HTMLInputElement) => void,

  // If both of these are non-falsy, you will get an extra
  // `x` button that clears the current value of the control.
  onClear?: () => void,
  clearButtonLabel?: string,

  /* This is a controlled component. */
  value?: ?ValueType,
  onChange?: (rawValue?: ValueType, maskedValue?: string) => void,

  /* Optional extra information about the control */
  error?: FormFieldError,
  success?: Node,
  description?: Node,

  /**
   * Only used if type === custom
   * Escape hatch. If you need to use this, let's talk about why
   * the existing `type` options are insufficient.
   */
  customMaskOptions?: MaskedTextInputOptions,

  /**
   * Only used if type === password, in which case it's
   * required for a11y reasons.
   */
  hideValueButtonLabel?: string,
  revealValueButtonLabel?: string,

  /** Only used if type === currency */
  currencyCode?: CurrencyCode, // Defaults to CAD
  decimalPlaces?: number, // Defaults to 2.
|};
