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

const MIN_TO_S = 60
const S_TO_MS = 1000

/**
 * The engine that manages the popup queue and the current popup.
 * The component using showPopup is responsible for rendering a close button.
 */
const PopupEngine = ({ children }: PropsWithChildren) => {
  const [queue, setQueue] = useState<ShowPopupProps[]>([])

  // 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(props => {
    setQueue(prev => [...prev, props])
  }, [])
  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].duration * 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(() => {
    if (queue.length === 0) {
      return
    }

    const { getContent, title, icon } = queue[0]

    return (
      <Dialog
        className={variableHeightMaximizedDialog}
        isOpen={isOpen}
        canEscapeKeyClose={false}
        canOutsideClickClose={false}
        isCloseButtonShown={false}
        title={title || ''}
        icon={icon}
        onClose={handleClose}
      >
        <DialogBody className={dialogBody}>
          {getContent(handleClose)}
        </DialogBody>
        <DialogFooter>
          <span>{`The popup will close in ${timedFormatterSecondsLeft(secondsLeft)}`}</span>
        </DialogFooter>
      </Dialog>
    )
  }, [queue, isOpen, handleClose, secondsLeft])

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

export default PopupEngine
