import { useEffect, useRef, ChangeEvent, FocusEvent, FocusEventHandler, ChangeEventHandler } from 'react'
import Input from '../input.js'
import { useField } from 'formik'
import { toUsdMoney, toNumber, dollarsToCents, centsToDollars } from '@navinc/utils'
import { InferComponentProps } from '../types.js'

const negativeNumberRegExp = /^(\$ )?0?-0?$/
const { abs, trunc } = Math

type UsdInputProps = InferComponentProps<typeof Input> & {
  name: string
  onBlur?: FocusEventHandler<HTMLInputElement>
  onChange?: ChangeEventHandler<HTMLInputElement>
  invalidOnTouched?: boolean
  allowNegatives?: boolean
}

const UsdInput = ({
  name,
  onBlur,
  onChange,
  invalidOnTouched = true,
  allowNegatives = false,
  ...props
}: UsdInputProps) => {
  const isNegativeRef = useRef(false)
  const [field, meta, { setValue }] = useField({ name })

  const toNumberOrZero = (input) => {
    const number = toNumber(input) || 0
    return trunc(allowNegatives ? number : abs(number))
  }

  useEffect(() => {
    // Ensure initial value stored in parent form is a number
    setValue(toNumberOrZero(field.value))
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const value =
    allowNegatives && isNegativeRef.current && field.value === 0 ? '$ -' : toUsdMoney(centsToDollars(field.value))

  return (
    <Input
      type="text"
      name={name}
      value={value}
      onChange={(e: ChangeEvent<HTMLInputElement>) => {
        const { target } = e
        const { value } = target
        isNegativeRef.current = negativeNumberRegExp.test(value)
        setValue(dollarsToCents(toNumberOrZero(value)))
        onChange && onChange(e)
      }}
      onBlur={(e: FocusEvent<HTMLInputElement>) => {
        isNegativeRef.current = false
        field.onBlur(e)
        onBlur && onBlur(e)
      }}
      errors={(!invalidOnTouched || meta.touched) && meta.error}
      isInvalid={(!invalidOnTouched || meta.touched) && !!meta.error}
      hasSpaceForErrors
      {...props}
    />
  )
}

export default UsdInput
