import React from 'react'

import PropTypes from 'prop-types'
import { InputLabel } from '../InputLabel/InputLabel'
import { Feedback } from '../Feedback/Feedback'
import { StackView } from '../StackView/StackView'
import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
import { useInputSupports } from './useInputSupports'
import { getTokensPropType } from '../utils/props/tokens'
import { useCopy } from '../utils/useCopy'
import { dictionary } from './dictionary'
import { propTypes as tooltipPropTypes } from '../Tooltip/shared'

export const InputSupports = React.forwardRef(
  (
    {
      children,
      copy = 'en',
      label,
      hint,
      hintPosition = 'inline',
      feedback,
      feedbackTokens = {},
      feedbackProps = {},
      tooltip,
      validation,
      maxCharacterAllowed,
      inputValue,
      nativeID
    },
    ref
  ) => {
    const { space } = useThemeTokens('InputSupports')
    const getCopy = useCopy({ dictionary, copy })

    const maxCharsReachedErrorMessage =
      inputValue?.length > maxCharacterAllowed
        ? getCopy('maxCharsMessage').replace(/%\{charCount\}/g, maxCharacterAllowed)
        : ''

    const feedbackValidation = inputValue?.length > maxCharacterAllowed ? 'error' : validation

    const { inputId, hintId, feedbackId, a11yProps } = useInputSupports({
      feedback,
      hint,
      label,
      validation,
      nativeID,
      copy,
      maxCharacterAllowed,
      charactersCount: maxCharacterAllowed - inputValue?.length
    })

    return (
      <StackView space={space} ref={ref}>
        {label && (
          <InputLabel
            copy={copy}
            label={label}
            hint={hint}
            hintPosition={hintPosition}
            hintId={hintId}
            tooltip={tooltip}
            forId={inputId}
            characterCount={inputValue?.length}
            maxCharacterAllowed={maxCharacterAllowed}
          />
        )}
        {typeof children === 'function'
          ? children({ inputId, ...a11yProps, validation: feedbackValidation })
          : children}
        {feedback || maxCharsReachedErrorMessage ? (
          <Feedback
            id={feedbackId}
            title={feedback || maxCharsReachedErrorMessage}
            validation={feedbackValidation}
            tokens={feedbackTokens}
            variant={{ icon: feedbackProps.showFeedbackIcon }}
            {...feedbackProps}
          />
        ) : null}
      </StackView>
    )
  }
)
InputSupports.displayName = 'InputSupports'

InputSupports.propTypes = {
  /**
   * The input these supports wrap. A render function receives `inputId`, the accessibility props
   * to spread onto the input, and the resolved `validation` state.
   */
  children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
  /**
   * Whether the English or French copy will be used (e.g. for accessibility labels).
   */
  copy: PropTypes.oneOf(['en', 'fr']),
  /**
   * The input label.
   */
  label: PropTypes.string,
  /**
   * A short description of the expected input.
   */
  hint: PropTypes.string,
  /**
   * Position of the hint relative to label.
   */
  hintPosition: PropTypes.oneOf(['inline', 'below']),
  /**
   * A detailed description of validation error/success or additional instructions.
   * Visual variant is determined based on the `validation` prop.
   */
  feedback: PropTypes.string,
  /**
   * Additional tokens to override the default feedback tokens.
   */
  feedbackTokens: getTokensPropType('Feedback'),
  /**
   * Additional props to pass to the `Feedback` component.
   */
  feedbackProps: PropTypes.object,
  /**
   * an optional `Tooltip`. If set, tooltip will be shown next to the label.
   * Props can be passed to the tooltip in one of the following ways.
   * 1. `tooltip` as a string - The content of the tooltip.
   * 2. `tooltip` as an object - Tooltip component props to be passed.
   */
  tooltip: PropTypes.oneOfType([PropTypes.shape(tooltipPropTypes), PropTypes.string]),
  /**
   * Use to visually mark an input as valid or invalid.
   */
  validation: PropTypes.oneOf(['error', 'success']),
  /**
   * ID for DOM element on web
   */
  nativeID: PropTypes.string,
  /**
   * The text value of a TextArea or TextInput
   */
  inputValue: PropTypes.string,
  /**
   * Max number of characters that allows an input text.
   */
  maxCharacterAllowed: PropTypes.number
}
