import {
  createContext,
  useContext,
  useState,
  useCallback,
  useMemo,
} from 'react';
import { useGlobal } from 'hooks/useGlobal';
import { Container } from 'components/notifications/Container';

const { NODE_ENV } = process.env;

export interface NotificationItem {
  id: string | number;
  type?: 'message' | 'error';
  title?: string;
  message: string;
  dismissAfter: number;
}

interface AddNotification {
  (message: string | NotificationItem): string | number;
}

export interface RemoveNotification {
  (id: string | number): void;
}

const WINDOW_NOTIFY = 'fansifter_notify';
const DEFAULT_PROPS: Partial<NotificationItem> = {
  type: 'message',
  dismissAfter: 5000,
};

export const NotificationsContext = createContext<{
  push: AddNotification;
} | null>(null);

export const useNotifications = () => {
  const context = useContext(NotificationsContext);
  if (context === null) {
    throw new Error(
      'useNotifications must be used within a NotificationsProvider'
    );
  }
  return context;
};

export const NotificationsProvider = ({
  children,
}: {
  children: React.ReactNode;
}) => {
  const [state, setState] = useState<NotificationItem[]>([]);

  const add: AddNotification = useCallback((notification) => {
    const item = { ...DEFAULT_PROPS };

    if (typeof notification === 'string') {
      item.message = notification;
    } else if (notification?.message) {
      Object.assign(item, notification);
    }

    if (!item.id) {
      item.id = new Date().getTime();
    }

    if (NODE_ENV === 'development') {
      item.dismissAfter = 0;
    }

    // if (item.dismissAfter) {
    //   item.dismissAfter = parseInt(item.dismissAfter, 10);
    // }

    setState((state) => [...state, item as NotificationItem]);

    return item.id;
  }, []);

  const remove = (id: string | number) => {
    setState((items) => items.filter((m) => m.id !== id));
  };

  useGlobal(WINDOW_NOTIFY, add);

  const value = useMemo(() => ({ push: add }), [add]);

  return (
    <NotificationsContext.Provider value={value}>
      {children}
      <Container items={state} remove={remove} />
    </NotificationsContext.Provider>
  );
};

// TODO refactor arguments
export function notify(title?: string, message?: string) {
  if ((window as any)[WINDOW_NOTIFY]) {
    const notification: Partial<NotificationItem> = {
      type: 'error',
      title,
      message,
    };

    (window as any)[WINDOW_NOTIFY](notification);
  }
}

export default NotificationsProvider;
