import { useEffect, useRef } from 'react'

type EventType = keyof WindowEventMap | keyof DocumentEventMap
type EventHandler<E extends Event> = (event: E) => void
type EventOptions = boolean | AddEventListenerOptions

function useEventListener<E extends Event>(
  eventName: EventType,
  handler: EventHandler<E>,
  element?: HTMLElement | Window | Document | null,
  options?: EventOptions
) {
  const savedHandler = useRef<EventHandler<E>>(handler)

  useEffect(() => {
    savedHandler.current = handler
  }, [handler])

  useEffect(() => {
    const target = element ?? window
    if (!(target && target.addEventListener)) return

    const eventListener = (event: Event) => {
      if (savedHandler.current) {
        savedHandler.current(event as E)
      }
    }

    target.addEventListener(eventName, eventListener, options)

    return () => {
      target.removeEventListener(eventName, eventListener, options)
    }
  }, [eventName, element, options])
}

export default useEventListener
