import { createContext, type FC, useEffect, useRef, useState } from 'react';

import isNil from 'lodash-es/isNil';

import useGeneralError from 'src/hooks/useGeneralError';
import { useNotificationLogoutCleanup } from 'src/pages/dashboard/notifications/hooks/useNotificationLogoutCleanup';
import {
  checkAndRequestPermission,
  getMessagingToken,
  isMessagingSupported,
  onMessage,
  registerNotificationToken,
} from 'src/pages/dashboard/notifications/services';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';

export type NotificationsContextValue = {
  notificationsToken: string | null;
};

const NotificationsContext = createContext<NotificationsContextValue>({
  notificationsToken: null,
});

export const NotificationsProvider: FC<
  React.PropsWithChildren<unknown>
> = props => {
  const { children } = props;

  const [notificationsToken, setNotificationsToken] = useState<string | null>(
    null,
  );
  const fetchedRef = useRef(false);

  const { t } = useTranslation();
  const showGeneralError = useGeneralError();

  useNotificationLogoutCleanup(notificationsToken, setNotificationsToken);

  useEffect(() => {
    const fetchMessagingToken = async () => {
      let supported;
      try {
        supported = await isMessagingSupported();
        const authorized = await checkAndRequestPermission();
        if (!supported || !authorized) return;

        const messagingToken = await getMessagingToken();

        if (messagingToken) {
          await registerNotificationToken(messagingToken);
          setNotificationsToken(messagingToken);

          onMessage(payload => {
            const { title, body } = payload.notification || {};

            if (
              title &&
              body &&
              localStorage.getItem('lastNotificationBody') !== body
            ) {
              localStorage.setItem('lastNotificationBody', body);
              // eslint-disable-next-line no-new
              new Notification(title, {
                body,
                tag: title,
              });
            }
          });
        }
      } catch (err) {
        showGeneralError(err, t('ERROR_CONNECTING_NOTIFICATIONS'));
      }
    };

    if (fetchedRef.current === false) {
      fetchedRef.current = true;
      isNil(notificationsToken) && fetchMessagingToken();
    }
  }, [notificationsToken, showGeneralError, t]);

  return (
    <NotificationsContext.Provider
      value={{
        notificationsToken,
      }}
    >
      {children}
    </NotificationsContext.Provider>
  );
};

export const SocketConsumer = NotificationsContext.Consumer;

export default NotificationsContext;
