import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { ToastOptions, ToastType } from './utils';
import { Button } from 'common/components/button';
import { Body } from 'common/components/typography';
import { bemClass, SToast } from './s-toast';
import { removeToast } from 'common/actions';
import { useDispatch } from 'react-redux';
import { bem } from 'utils/bem';
import { Icon } from '../icon';
import { IconName } from '../icon/types';
import { renderToString } from 'react-dom/server';

const AUTO_DISMISSING_TIMEOUT_TIME = 5000;
const AUTO_DISMISSING_SUCCESS_TIMEOUT_TIME = 2000;
const TOTAL_TIMEOUT_TIME = 30000;

const classes = bem(bemClass);

export const Toast = React.memo(
  ({ id, type, dataSelector = ToastType[type].toLowerCase(), message, onUndo }: ToastOptions) => {
    const timeoutRef = useRef<NodeJS.Timeout>();
    const toastRef = useRef<HTMLDivElement>(null);
    const dispatch = useDispatch();

    const toastIcon = useMemo(() => {
      const getIcon = (name: IconName) => <Icon className={classes('icon')} color="white" name={name} size="large" />;

      switch (type) {
        case ToastType.Success:
          return getIcon('success');
        case ToastType.Error:
          return getIcon('error');
        case ToastType.Warning:
          return getIcon('warning');
        case ToastType.Info:
          return getIcon('info');
        default:
          return null;
      }
    }, [type]);

    const onCloseClick = useCallback(() => {
      dispatch(removeToast(id));
    }, [dispatch, id]);

    const onUndoClick = useCallback(() => {
      dispatch(removeToast(id));
      onUndo && onUndo();
    }, [dispatch, onUndo, id]);

    useEffect(() => {
      const timeout = setTimeout(() => dispatch(removeToast(id)), TOTAL_TIMEOUT_TIME);

      return () => clearTimeout(timeout);
    }, [dispatch, id]);

    useEffect(() => {
      const toastElement = toastRef && toastRef.current;

      const startTimeout = () => {
        timeoutRef.current = setTimeout(
          () => dispatch(removeToast(id)),
          type === ToastType.Success ? AUTO_DISMISSING_SUCCESS_TIMEOUT_TIME : AUTO_DISMISSING_TIMEOUT_TIME
        );
      };

      const stopTimeout = () => {
        timeoutRef.current && clearTimeout(timeoutRef.current);
      };

      startTimeout();

      if (toastElement) {
        toastElement.addEventListener('mouseenter', stopTimeout);
        toastElement.addEventListener('mouseleave', startTimeout);
      }

      return () => {
        stopTimeout();

        if (toastElement) {
          toastElement.removeEventListener('mouseenter', stopTimeout);
          toastElement.removeEventListener('mouseleave', startTimeout);
        }
      };
    }, [dispatch, id, type]);

    const messageToString = useMemo(
      () =>
        typeof message === 'string' || typeof message === 'number'
          ? message.toString()
          : renderToString(message).replace(/<[^>]+>/g, ''),
      [message]
    );
    return (
      <SToast ref={toastRef} id={id} type={type} data-selector={`${dataSelector}-toast`}>
        {toastIcon}
        <Body className={classes('message')} title={messageToString} data-selector="toast-message">
          {message}
        </Body>
        {onUndo && (
          <button onClick={onUndoClick} className={classes('undo')}>
            Undo
          </button>
        )}
        <Button
          variant="transparent"
          className={classes('close')}
          onClick={onCloseClick}
          dataSelector="toast-close-button"
        >
          <Icon color="white" name="close" size="general" />
        </Button>
      </SToast>
    );
  }
);
