import { mount } from 'enzyme'
import React from 'react'
import {
  getProps,
  testContext,
  testRenderProp,
} from '../../__tests__/helpers/state'
import {
  BoundingRect,
  BoundingRectProvider,
  DEFAULT_RECT,
  useBoundingRect,
  useBoundingRectContext,
} from '../BoundingRect'

const Component = 'div'

const validateAPI = (api) => {
  expect(api.ref).toBeTruthy()
  expect(api.rect).toBeInstanceOf(Object)
}

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

const Enhanced = ({ width, dependencies }) => {
  const mockGetBoundingClientRect = jest
    .spyOn(Element.prototype, 'getBoundingClientRect')
    .mockImplementation(() => ({
      ...DEFAULT_RECT,
      width,
    }))

  const boundingRect = useBoundingRect({ dependencies })

  React.useLayoutEffect(mockGetBoundingClientRect.mockRestore)

  return (
    <Component ref={boundingRect.ref} state={boundingRect} style={{ width }} />
  )
}

describe('BoundingRect', () => {
  describe('hook', () => {
    it('provides the correct api', () => {
      const width = 100
      const dom = mount(<Enhanced width={width} />)
      const props = getProps(Component, dom, 'state')()

      validateAPI(props)

      expect(props.rect.width).toBe(100)
    })

    it('updates rect when changing dependencies', () => {
      const width1 = 100
      const width2 = 200
      const dom = mount(<Enhanced width={width1} dependencies={[true]} />)
      const props = getProps(Component, dom, 'state')

      expect(props().rect.width).toBe(width1)

      dom.setProps({ width: width2, dependencies: [false] })

      expect(props().rect.width).toBe(width2)
    })
  })

  testRenderProp(BoundingRect, 'boundingRect', [apiTest])

  testContext(BoundingRectProvider, useBoundingRectContext, [
    apiTest,
    {
      test: 'missing provider',
      config: {},
      injectProvider: false,
      callback: ({ ref, rect }) => {
        expect(ref).toEqual({ current: null })
      },
    },
  ])
})
