import { ChangeEvent, FocusEvent, FocusEventHandler, ChangeEventHandler, useMemo } from 'react'
import Input from '../input.js'
import { useField, FieldValidator } from 'formik'
import { isValidEmail } from '@navinc/utils'
import { InferComponentProps } from '../types.js'

const createEmailValidator =
  ({
    isRequired = false,
    requiredErrorMessage = 'Required',
    invalidErrorMessage = 'Please enter a valid email address',
  } = {}) =>
  (address: string): [string] | void => {
    if (isRequired && !address) {
      return [requiredErrorMessage]
    }

    if (address && !isValidEmail(address)) {
      return [invalidErrorMessage]
    }
  }

type EmailInputProps = InferComponentProps<typeof Input> &
  Parameters<typeof createEmailValidator>[0] & {
    name: string
    onBlur?: FocusEventHandler<HTMLInputElement>
    onChange?: ChangeEventHandler<HTMLInputElement>
    invalidOnTouched?: boolean
  }

export const EmailInput = ({
  name,
  onBlur,
  onChange,
  invalidOnTouched = true,
  isRequired,
  requiredErrorMessage,
  invalidErrorMessage,
  ...props
}: EmailInputProps) => {
  const memoizedValidateEmail = useMemo(
    () => createEmailValidator({ isRequired, requiredErrorMessage, invalidErrorMessage }),
    [isRequired, requiredErrorMessage, invalidErrorMessage]
  )
  const [field, meta] = useField({ name, validate: memoizedValidateEmail as FieldValidator })

  return (
    <Input
      type="email"
      name={name}
      value={field.value}
      onChange={(e: ChangeEvent<HTMLInputElement>) => {
        field.onChange(e)
        onChange && onChange(e)
      }}
      onBlur={(e: FocusEvent<HTMLInputElement>) => {
        field.onBlur(e)
        onBlur && onBlur(e)
      }}
      errors={(!invalidOnTouched || meta.touched) && meta.error}
      isInvalid={(!invalidOnTouched || meta.touched) && !!meta.error}
      hasSpaceForErrors
      {...props}
    />
  )
}
