import { Button, Dialog, DialogBody, DialogFooter } from '@blueprintjs/core'
import type { PropsWithChildren, ReactNode } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { dialogBody, variableHeightMaximizedDialog } from '../css/dialog'
import { PopupProvider } from './PopupContext'
import type { PopupContextProps, ShowPopupFunction } from './typing'

const MIN_TO_S = 60
const S_TO_MS = 1000

const PopupEngine = ({ children }: PropsWithChildren) => {
  const [queue, setQueue] = useState<Parameters<typeof showPopup>[]>([])

  // state of the current popup
  const [isOpen, setIsOpen] = useState(false)
  const [secondsLeft, setSecondsLeft] = useState(0)
  // ----------------------------

  const handleClose = useCallback(() => {
    setIsOpen(false)
    setSecondsLeft(0)
    setQueue(prev => prev.slice(1))
  }, [])

  // add the popup to the queue
  const showPopup: ShowPopupFunction = useCallback(
    (duration: number, content: ReactNode) => {
      setQueue(prev => [...prev, [duration, content]])
    },
    []
  )
  const value = useMemo<PopupContextProps>(() => ({ showPopup }), [showPopup])

  // show the next popup in the queue, if possible
  useEffect(() => {
    // the popup is already open or the queue is empty, do nothing
    if (isOpen || queue.length === 0) {
      return
    }

    // show the next popup in the queue
    setIsOpen(true)
    setSecondsLeft(queue[0][0] * MIN_TO_S)
  }, [isOpen, queue])

  // close the popup after the duration
  useEffect(() => {
    // the duration is over, close the popup
    if (isOpen && secondsLeft === 0) {
      handleClose()
    }

    // the popup was just opened, start the countdown
    if (isOpen) {
      const interval = setInterval(() => {
        setSecondsLeft(prev => prev - 1)
      }, S_TO_MS)

      return () => clearInterval(interval)
    }
  }, [isOpen, secondsLeft, handleClose])

  const popupProvider = useMemo(
    () => <PopupProvider value={value}>{children}</PopupProvider>,
    [children, value]
  )
  const dialog = useMemo(
    () => (
      <>
        {queue.length > 0 && (
          <Dialog
            className={variableHeightMaximizedDialog}
            isOpen={isOpen}
            canEscapeKeyClose={false}
            canOutsideClickClose={false}
          >
            <DialogBody className={dialogBody}>{queue[0][1]}</DialogBody>
            <DialogFooter
              actions={
                <Button text='Close' intent='primary' onClick={handleClose} />
              }
            >
              <span>{`The popup will close in ${new Date(secondsLeft * S_TO_MS).toISOString().substring(11, 19)}`}</span>
            </DialogFooter>
          </Dialog>
        )}
      </>
    ),
    [isOpen, queue, handleClose, secondsLeft]
  )

  return (
    <>
      {popupProvider}
      {dialog}
    </>
  )
}

export default PopupEngine
