import PropTypes from 'prop-types';
import React, { useState, useEffect, useCallback } from 'react';

import { Container, Content, Banner, Text, Icon } from './styledComponents';

import { Props, ToasterInterface } from './interfaces';
import {
  TOASTER_STATUS,
  TOASTER_POSITION,
  TOASTER_CUSTOM_ICON,
} from './constants';

import iconClose from '../images/icon-close-cross.svg';
import iconToasterError from '../images/icon-toaster-error.svg';
import iconToasterSuccess from '../images/icon-toaster-success.svg';
import iconToasterWarning from '../images/icon-toaster-warning.svg';
import iconToasterInfo from '../images/icon-toaster-info.svg';

import ColorPalette from '../utils/colorPalette';

const getBackgroundColor = (status?: string): ColorPalette => {
  if (status === TOASTER_STATUS.ERROR) {
    return ColorPalette.Info_Red;
  }
  if (status === TOASTER_STATUS.WARNING) {
    return ColorPalette.Info_Orange;
  }
  if (status === TOASTER_STATUS.INFO) {
    return ColorPalette.DMGrey;
  }

  return ColorPalette.Info_Green;
};

const renderIcon = (icon, status): JSX.Element | null => {
  if (icon && TOASTER_CUSTOM_ICON[icon]) {
    return <Icon src={TOASTER_CUSTOM_ICON[icon]} alt="icon-custom" />;
  }

  if (status === TOASTER_STATUS.ERROR) {
    return <Icon src={iconToasterError} alt="icon-error" />;
  }

  if (status === TOASTER_STATUS.INFO) {
    return <Icon src={iconToasterInfo} alt="icon-info" />;
  }

  if (status === TOASTER_STATUS.WARNING) {
    return <Icon src={iconToasterWarning} alt="icon-warning" />;
  }

  return <Icon src={iconToasterSuccess} alt="icon-success" />;
};

const Toaster = (props: Props): JSX.Element | null => {
  const {
    icon,
    text,
    status,
    hidden,
    position,
    autoDelete,
    dismissTime,
    handleClose,
  } = props;

  const [hideToaster, setHideToaster] = useState<boolean>(true);
  const [toaster, setToaster] = useState<ToasterInterface | null>(null);

  const deleteToast = useCallback(() => {
    if (handleClose) {
      handleClose();
    }

    setHideToaster(true);
  }, [handleClose]);

  useEffect(() => {
    if (hideToaster) {
      return;
    }

    setToaster({
      text,
      status,
      position,
    });
  }, [text, status, position, hideToaster]);

  useEffect(() => {
    if (hideToaster !== hidden) {
      setHideToaster(hidden);
    }
  }, [hidden, hideToaster, setHideToaster]);

  useEffect(() => {
    const timeout = setTimeout(() => {
      if (autoDelete && !!toaster) {
        deleteToast();
      }
    }, dismissTime);

    return () => {
      clearTimeout(timeout);
    };
  }, [toaster, autoDelete, dismissTime, deleteToast]);

  if (!toaster) {
    return <></>;
  }

  return (
    <Container
      data-testid="container"
      position={!hideToaster ? toaster.position : `${position}-fade-out`}
    >
      <Banner
        data-testid="banner"
        hidden={hideToaster}
        enabledAnimation={autoDelete}
        transitionTime={dismissTime / 1000}
        backgroundColor={getBackgroundColor(toaster.status)}
      />
      <Content>
        {renderIcon(icon, toaster.status)}
        <Text>{toaster.text}</Text>
        {handleClose && (
          <Icon
            hoverable
            data-testid="icon-close"
            src={iconClose}
            alt="icon-close"
            onClick={deleteToast}
          />
        )}
      </Content>
    </Container>
  );
};

Toaster.propTypes = {
  autoDelete: PropTypes.bool,
  handleClose: PropTypes.func,
  dismissTime: PropTypes.number,
  hidden: PropTypes.bool.isRequired,
  text: PropTypes.string.isRequired,
  status: PropTypes.oneOf(Object.values(TOASTER_STATUS)),
  icon: PropTypes.oneOf(Object.keys(TOASTER_CUSTOM_ICON)),
  position: PropTypes.oneOf(Object.values(TOASTER_POSITION)),
};

Toaster.defaultProps = {
  icon: null,
  autoDelete: false,
  dismissTime: 3000,
  handleClose: null,
  status: TOASTER_STATUS.SUCCESS,
  position: TOASTER_POSITION.BOTTOM_LEFT,
};

export default Toaster;
