import { screen, fireEvent, waitFor } from '@testing-library/react'
import { Formik, Form } from 'formik'
import { renderWithContext } from '../tests/with-app-context.js'
import { UsdInput } from './usd-input.js'

describe('Base Components: UsdInput', () => {
  it('renders errors if there are any', async () => {
    const testId = 'usd-input-test-id'

    renderWithContext(
      <Formik
        initialValues={{
          test: 123456,
        }}
        validate={({ test }) => ({
          ...(test < 200 && { test: ['Must be greater than $1'] }),
        })}
        onSubmit={() => {}}
      >
        <UsdInput name="test" data-testid={testId} />
      </Formik>
    )

    const input = screen.getByTestId(testId) as HTMLInputElement

    expect(screen.queryByText('Must be greater than $1')).not.toBeInTheDocument()

    fireEvent.change(input, { target: { value: '0.25' } })
    fireEvent.blur(input)

    await screen.findByText('Must be greater than $1')

    fireEvent.change(input, { target: { value: '2.25' } })
    fireEvent.blur(input)

    await waitFor(() => expect(screen.queryByText('Must be greater than $1')).not.toBeInTheDocument())
  })

  it('can render negative values', async () => {
    const testId = 'usd-input-test-id'

    renderWithContext(
      <Formik
        initialValues={{
          test: 0,
        }}
        onSubmit={() => {}}
      >
        <UsdInput name="test" data-testid={testId} allowNegatives />
      </Formik>
    )

    const input = screen.getByTestId(testId) as HTMLInputElement

    await waitFor(() => expect(input.value).toBe('$0'))

    fireEvent.change(input, { target: { value: '$0-' } })

    await waitFor(() => expect(input.value).toBe('$0'))

    fireEvent.change(input, { target: { value: '$-5' } })

    await waitFor(() => expect(input.value).toBe('$-5'))
  })

  it('will not render negative values by default', async () => {
    const testId = 'usd-input-test-id'

    renderWithContext(
      <Formik
        initialValues={{
          test: 0,
        }}
        onSubmit={() => {}}
      >
        <UsdInput name="test" data-testid={testId} />
      </Formik>
    )

    const input = screen.getByTestId(testId) as HTMLInputElement

    await waitFor(() => expect(input.value).toBe('$0'))

    fireEvent.change(input, { target: { value: '$0-' } })

    await waitFor(() => expect(input.value).toBe('$0'))

    fireEvent.change(input, { target: { value: '$-5' } })

    await waitFor(() => expect(input.value).toBe('$5'))
  })

  it('displays dollars, but accepts cents and outputs cents', async () => {
    const testId = 'usd-input-test-id'
    const handleSubmit = jest.fn()

    renderWithContext(
      <Formik
        initialValues={{
          test: 123456,
        }}
        onSubmit={handleSubmit}
      >
        <Form>
          <UsdInput name="test" data-testid={testId} />
          <button type="submit">Submit</button>
        </Form>
      </Formik>
    )

    const input = screen.getByTestId(testId) as HTMLInputElement

    expect(input.value).toBe('$1,235')

    fireEvent.change(input, { target: { value: '8765' } })

    await waitFor(() => expect(input.value).toBe('$8,765'))

    fireEvent.click(screen.getByRole('button', { name: /submit/i }))

    await waitFor(() => expect(handleSubmit).toHaveBeenCalledWith({ test: 876500 }, expect.anything()))
  })
})
