import { useEffect, useState } from 'react'

type LazyLoader = () => Promise<unknown>

export const MODAL_EXIT_DURATION_MS = 240

export function useLazyMount(
  open: boolean,
  unmountDelayMs = MODAL_EXIT_DURATION_MS,
) {
  const [shouldMount, setShouldMount] = useState(open)

  useEffect(() => {
    if (open) {
      setShouldMount(true)
      return
    }

    if (!shouldMount) {
      return
    }

    const timeoutId = setTimeout(() => {
      setShouldMount(false)
    }, unmountDelayMs)

    return () => {
      clearTimeout(timeoutId)
    }
  }, [open, shouldMount, unmountDelayMs])

  return shouldMount
}

export function useDeferredModalPayload<T>(
  payload: T | null,
  clearDelayMs = MODAL_EXIT_DURATION_MS,
) {
  const [renderPayload, setRenderPayload] = useState<T | null>(payload)

  useEffect(() => {
    if (payload !== null) {
      setRenderPayload(payload)
      return
    }

    const timeoutId = setTimeout(() => {
      setRenderPayload(null)
    }, clearDelayMs)

    return () => {
      clearTimeout(timeoutId)
    }
  }, [payload, clearDelayMs])

  return renderPayload
}

export function preloadOnIdle(loaders: LazyLoader[]) {
  if (typeof window === 'undefined') return () => undefined

  let cancelled = false
  let timeoutId: number | undefined
  let idleId: number | undefined

  function preload() {
    if (cancelled) return

    loaders.forEach((loader) => {
      void loader()
    })
  }

  if ('requestIdleCallback' in window) {
    idleId = window.requestIdleCallback(preload, {
      timeout: 2500,
    })
  } else {
    timeoutId = setTimeout(preload, 900)
  }

  return () => {
    cancelled = true

    if (idleId !== undefined && 'cancelIdleCallback' in window) {
      window.cancelIdleCallback(idleId)
    }

    if (timeoutId !== undefined) {
      clearTimeout(timeoutId)
    }
  }
}
