import { createRef } from 'react';
import {
  type OptionsObject,
  type ProviderContext,
  type SnackbarMessage,
  type VariantType,
  type SnackbarKey,
  type SnackbarProviderProps,
  SnackbarProvider,
  useSnackbar,
} from 'notistack';
import { IconButton } from '@mui/material';
import { Close as CloseIcon } from '@mui/icons-material';
import noop from 'lodash/noop';

type EnqueueSnackbar = ProviderContext['enqueueSnackbar'];

let success = noop as EnqueueSnackbar;
let error = noop as EnqueueSnackbar;
let warning = noop as EnqueueSnackbar;
let info = noop as EnqueueSnackbar;
let close: (key?: SnackbarKey) => void = noop;

const genFn =
  (enqueueSnackbar: EnqueueSnackbar, variant: VariantType) =>
  (message: SnackbarMessage, opts: OptionsObject = {}) =>
    enqueueSnackbar(message, {
      autoHideDuration: 5000,
      variant,
      ...opts,
    });

function ToastProvider({ children, anchorOrigin, ...rest }: Omit<SnackbarProviderProps, 'ref' | 'action'>) {
  const notistackRef = createRef<SnackbarProvider>();
  const onClickDismiss = (key: SnackbarKey) => () => {
    notistackRef.current?.closeSnackbar(key);
  };

  return (
    <SnackbarProvider
      anchorOrigin={{
        vertical: 'top',
        horizontal: 'right',
        ...anchorOrigin,
      }}
      {...rest}
      ref={notistackRef}
      // eslint-disable-next-line react/no-unstable-nested-components
      action={(key) => (
        <IconButton key="close" aria-label="close" color="inherit" onClick={onClickDismiss(key)} size="large">
          <CloseIcon style={{ fontSize: 16 }} />
        </IconButton>
      )}>
      <Toast />
      {children}
    </SnackbarProvider>
  );
}

function Toast() {
  const { enqueueSnackbar, closeSnackbar } = useSnackbar();

  success = genFn(enqueueSnackbar, 'success');
  error = genFn(enqueueSnackbar, 'error');
  warning = genFn(enqueueSnackbar, 'warning');
  info = genFn(enqueueSnackbar, 'info');
  close = closeSnackbar;

  return null;
}

export { ToastProvider };

export default {
  success: (message: SnackbarMessage, options: OptionsObject = {}) => success(message, options),
  error: (message: SnackbarMessage, options: OptionsObject = { autoHideDuration: 15000 }) => error(message, options),
  warning: (message: SnackbarMessage, options: OptionsObject = {}) => warning(message, options),
  info: (message: SnackbarMessage, options: OptionsObject = {}) => info(message, options),
  close: (key?: SnackbarKey) => close(key),
};
