import NotificationListContext from '@inject/shared/notification/contexts/NotificationListContext'
import { NotifyProvider } from '@inject/shared/notification/contexts/NotifyContext'
import toaster from '@inject/shared/notification/toaster'
import type {
  NotifyContextProps,
  OmittedToastProps,
} from '@inject/shared/notification/typing'
import type { PropsWithChildren } from 'react'
import { useCallback, useMemo } from 'react'
import useNotificationStorage from './useNotificationStorage'

export const NotificationEngine = ({ children }: PropsWithChildren) => {
  const [notifications, setNotifications] = useNotificationStorage()

  const removeNotify = useCallback(
    (timestamp: number) => {
      setNotifications(
        prev =>
          prev?.filter(notification => notification.timestamp !== timestamp) ??
          []
      )
    },
    [setNotifications]
  )

  const notify = useCallback(
    (msg: string, toastProps?: OmittedToastProps, timestamp?: Date) => {
      const tm = timestamp?.valueOf() ?? Date.now()
      const props = toastProps ?? {}
      setNotifications(prev => [
        ...(prev ?? []),
        {
          intent: props.intent ?? 'success',
          msg,
          timestamp: tm,
        },
      ])
      toaster?.show({
        intent: 'success',
        timeout: 5000,
        onDismiss(didTimeoutExpire) {
          if (!didTimeoutExpire) {
            removeNotify(tm)
          }
        },
        message: msg,
        ...props,
      })
    },
    [setNotifications, removeNotify]
  )

  const clearNotify = useCallback(() => {
    setNotifications([])
  }, [setNotifications])

  const value = useMemo<NotifyContextProps>(
    () => ({
      notify,
      removeNotify,
      clearNotify,
    }),
    [notify, removeNotify, clearNotify]
  )

  return (
    <NotifyProvider value={value}>
      <NotificationListContext.Provider value={notifications}>
        {children}
      </NotificationListContext.Provider>
    </NotifyProvider>
  )
}

export default NotificationEngine
