// @ts-nocheck
import { h, createContext, type FunctionComponent } from 'preact'
import { useContext, useReducer } from 'preact/hooks'

type MessageType = 'error' | 'info' | 'success'

type Payload = {
  id: number
  message: string
  type: MessageType
  dismiss?: () => void
}

type Action = {
  type: typeof NOTIFY | typeof DISMISS
  payload: Payload
}

const NotificationsContext = createContext<{
  notifications: ANY[]
  notify: ((message: string, type?: MessageType, timeout?: number) => void) & {
    error: (message: string, timeout?: number) => void
    info: (message: string, timeout?: number) => void
    success: (message: string, timeout?: number) => void
  }
}>()

const NOTIFY = 'notify'

export const notifyAction = (message: string, type: MessageType): Action => ({
  type: NOTIFY,
  payload: {
    id: counter++,
    message,
    type,
  },
})

const DISMISS = 'dismiss'

export const dismissAction = (id: number) => ({
  type: DISMISS,
  id,
})

let counter = 0

export const reducer = (state: Payload[], action: Action) => {
  switch (action.type) {
    case NOTIFY:
      return state.concat(action.payload)
    case DISMISS: {
      const index = state.findIndex((notification) => notification.id === action.id)

      if (index > -1) {
        return [...state.slice(0, index), ...state.slice(index + 1)]
      }

      return state
    }
    default:
      return state
  }
}

export const useNotifications = () => useContext(NotificationsContext)

export const NotificationsProvider: FunctionComponent<{ defaultTimeout?: number }> = ({
  children,
  defaultTimeout = 0,
}) => {
  const [notifications, dispatch] = useReducer(reducer, [])

  function notify(message: string, type: MessageType = 'info', timeout = defaultTimeout) {
    const action = notifyAction(message, type)
    const dismiss = (action.payload.dismiss = () => dispatch(dismissAction(action.payload.id)))

    dispatch(action)

    if (timeout) {
      setTimeout(dismiss, timeout)
    }

    return dismiss
  }

  notify.error = (message: string, timeout?: number) => notify(message, 'error', timeout)
  notify.success = (message: string, timeout?: number) => notify(message, 'success', timeout)
  notify.info = (message: string, timeout?: number) => notify(message, 'info', timeout)

  return <NotificationsContext.Provider value={{ notifications, notify }}>{children}</NotificationsContext.Provider>
}
