import React from 'react'
import PropTypes from 'prop-types'
import { a11yProps } from '../utils/props/a11yProps'
import { focusHandlerProps, textInputHandlerProps } from '../utils/props/handlerProps'
import { getTokensPropType } from '../utils/props/tokens'
import { inputSupportsProps } from '../utils/props/inputSupportsProps'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { textInputProps } from '../utils/props/textInputProps'
import { variantProp } from '../utils/props/variantProp'
import { viewProps } from '../utils/props/viewProps'
import { InputSupports } from '../InputSupports/InputSupports'
import { TextInputBase } from './TextInputBase'
import { textInputPropTypes } from './propTypes'

const [selectProps, selectedSystemPropTypes] = selectSystemProps([
  a11yProps,
  focusHandlerProps,
  inputSupportsProps,
  textInputHandlerProps,
  textInputProps,
  viewProps
])

/**
 * A basic text input component. Use in forms or individually to receive user's input.
 * Due to React Native's implementation of `TextInput` it's not possible to access the current value by passing a ref.
 *
 * ## Controlled component
 * If it is required that the state of the `TextInput` be controlled by the application or other external methods,
 * `value` and `onChange` props must be passed to the `TextInput`.
 * If the `TextInput` value should not be changed by user input, a `readOnly` prop must be provided.
 *
 * ## Uncontrolled component
 * If it is not necessary to control the `TextInput` state, you can create one without a value prop.
 * In this case its value can be accessed within the `onChange` callback.
 *
 * NOTE: In order to support more advanced usages all additional props will be passed down to the React Native's
 * `TextInput` component. See <a href="https://reactnative.dev/docs/textinput" target="_blank">React Native documentation</a> for
 * supported props and <a href="https://reactnative.dev/docs/textinput" target="_blank">React Native Web documentation</a> for
 * their implementation on the web.
 */
export const TextInput = React.forwardRef(({ tokens, nativeID, variant = {}, ...rest }, ref) => {
  const { supportsProps, ...selectedProps } = selectProps(rest)

  const inputProps = {
    ...selectedProps,
    tokens
  }

  return (
    <>
      <InputSupports nativeID={nativeID} {...supportsProps} inputValue={selectedProps?.value}>
        {({ inputId, ...propsFromInputSupports }) => {
          return (
            <TextInputBase
              ref={ref}
              nativeID={inputId}
              {...propsFromInputSupports}
              {...inputProps}
              variant={{ ...variant, validation: propsFromInputSupports.validation }}
            />
          )
        }}
      </InputSupports>
      {rest.children}
    </>
  )
})
TextInput.displayName = 'TextInput'

TextInput.propTypes = {
  ...selectedSystemPropTypes,
  ...textInputPropTypes,
  /**
   * A callback which if provided will get a clear button rendered and will be called whenever that button gets pressed.
   */
  onClear: PropTypes.func,
  /**
   * Called when a key is pressed while the input has focus.
   */
  onKeyPress: PropTypes.func,
  tokens: getTokensPropType('TextInput'),
  variant: variantProp.propType
}
