import { mount } from 'enzyme'
import React from 'react'

import { useEventListener } from '../EventListener'

function noop() {}

const mockScope = () => {
  const listeners = {}

  const scope = {
    addEventListener: jest.fn((event, cb) => {
      listeners[event] = cb
    }),
    removeEventListener: jest.fn((event, cb) => {
      listeners[event] = null
    }),
  }

  return { current: scope }
}

const Enhanced = (props) => {
  useEventListener(props)

  return null
}

describe('useEventListener', () => {
  describe('scope changes', () => {
    const scopeA = mockScope()
    const scopeB = mockScope()

    mount(<Enhanced event="scroll" handler={noop} scope={scopeA} />).setProps({
      scope: scopeB,
    })

    it('adds and removes listeners to scope when scope changes', (done) => {
      setTimeout(() => {
        expect(scopeA.current.removeEventListener).toBeCalledTimes(1)
        expect(scopeB.current.addEventListener).toBeCalledTimes(1)
        done()
      }, 10)
    })
  })

  describe('event type changes', () => {
    const scope = mockScope()

    mount(<Enhanced event="scroll" handler={noop} scope={scope} />).setProps({
      event: 'resize',
    })

    it('adds and removes listeners from scope when event changes', (done) => {
      setTimeout(() => {
        expect(scope.current.addEventListener).toBeCalledTimes(2)
        expect(scope.current.removeEventListener).toBeCalledTimes(1)
        done()
      }, 10)
    })
  })

  describe('handler changes', () => {
    const scope = mockScope()

    mount(<Enhanced event="scroll" handler={noop} scope={scope} />).setProps({
      handler: () => {},
    })

    it('keeps the same listener when handler changes', (done) => {
      setTimeout(() => {
        expect(scope.current.addEventListener).toBeCalledTimes(1)
        expect(scope.current.removeEventListener).toBeCalledTimes(0)
        done()
      }, 10)
    })
  })
})
