import {
  testContext,
  testHook,
  testRenderProp,
} from '../../__tests__/helpers/state'
import {
  TextEntry,
  TextEntryProvider,
  useTextEntry,
  useTextEntryContext,
} from '../TextEntry'

const validateAPI = (api) => {
  expect(api.value).toEqual('')
  expect(api.empty).toEqual(true)
  expect(api.onChange).toBeInstanceOf(Function)
  expect(api.clear).toBeInstanceOf(Function)
  expect(api.reset).toBeInstanceOf(Function)
}

const apiTest = {
  test: 'api',
  config: {},
  callback: validateAPI,
}

const configTest = {
  test: 'config',
  config: { initialValue: 'foo', handler: jest.fn() },
  callback: ({ value }) => expect(value).toEqual('foo'),
}

const onChangeTest = () => {
  const onChange = jest.fn()

  return {
    test: 'handler',
    config: { onChange },
    callback: ({ reset }) => {
      reset()
      expect(onChange).toBeCalled()
    },
  }
}

describe('TextEntry', () => {
  testHook(useTextEntry, [
    apiTest,
    configTest,
    onChangeTest(),
    {
      test: 'mutations',
      config: { initialValue: 'foo' },
      mutations: [
        ['clear', null, ['value', 'toBe', '']],
        ['reset', null, ['value', 'toBe', 'foo']],
        ['reset', null, ['empty', 'toBe', false]],
      ],
    },
  ])

  testRenderProp(TextEntry, 'textEntry', [apiTest, configTest])

  testContext(TextEntryProvider, useTextEntryContext, [
    apiTest,
    configTest,
    {
      test: 'missing provider',
      config: {},
      injectProvider: false,
      callback: (context, { spy }) => {
        spy.mockImplementation(() => {})

        context.clear()
        context.reset()
        expect(spy).toBeCalledTimes(2)
        expect(spy).toHaveBeenNthCalledWith(
          1,
          'Could not call `clear`, please wrap your component in a `<TextEntryProvider>`'
        )
        expect(spy).toHaveBeenNthCalledWith(
          2,
          'Could not call `reset`, please wrap your component in a `<TextEntryProvider>`'
        )
        expect(context.value).toBe('')
        expect(context.empty).toBe(true)

        spy.mockRestore()
      },
    },
  ])
})
