import React, { useState, useMemo, createContext, useContext } from 'react';
import { createPortal } from 'react-dom';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import Icon from '../Icon';

const ProgressBar = styled.div`
  @keyframes progressBar {
    0% {
      transform: scaleX(1);
    }
    100% {
      transform: scaleX(0);
    }
  }
  background: ${props => props.progressBarColor};
  position: absolute;
  border-radius: 0px 0px 0px 6px;
  overflow: hidden;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 5px;
  z-index: 9999;
  transform-origin: left;
  animation-duration: 5000ms;
  opacity: 1;
  animation-name: progressBar;
  transform: scaleX(0);
`;

const Root = styled.div`
  position: relative;

  ${props =>
    props.absolute &&
    `
    position: absolute;
  `}

  ${props =>
    props.position === 'top-left' &&
    `
    top: 20px;
    left: 20px;
  `}

  ${props =>
    props.position === 'top-right' &&
    `
    top: 20px;
    right: 20px;
  `}

  ${props =>
    props.position === 'top-middle' &&
    `
    top: 20px;
    left: 50%;
    transform: translate(-50%);
  `}

  ${props =>
    props.position === 'bottom-left' &&
    `
    bottom: 20px;
    left: 20px;
  `}

  ${props =>
    props.position === 'bottom-right' &&
    `
    bottom: 20px;
    right: 20px;
  `}

  ${props =>
    props.position === 'bottom-middle' &&
    `
    bottom: 20px;
    left: 50%;
    transform: translate(-50%);
  `}

  margin-top: 16px;
  margin-bottom: 16px;
  display: flex;
  flex-direction: row;
  padding: 15px;
  width: 290px;
  max-width: 100vw;
  z-index: 2147483647;
  outline: none;
  box-shadow:
    hsl(206 22% 7% / 35%) 0px 10px 38px -10px,
    hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
  border-radius: 6px;
  align-items: center;
  cursor: pointer;
  background-color: ${props => props.backgroundColor};

  &:hover ${ProgressBar} {
    animation-play-state: paused;
  }

  @keyframes bounceInMiddle {
    from,
    20%,
    40%,
    60%,
    80%,
    to {
      animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    }

    0% {
      opacity: 0;
      transform: scale3d(0.3, 0.3, 0.3) translate(-50%);
    }

    20% {
      transform: scale3d(1.1, 1.1, 1.1) translate(-50%);
    }

    40% {
      transform: scale3d(0.9, 0.9, 0.9) translate(-50%);
    }

    60% {
      opacity: 1;
      transform: scale3d(1.03, 1.03, 1.03) translate(-50%);
    }

    80% {
      transform: scale3d(0.97, 0.97, 0.97) translate(-50%);
    }

    to {
      opacity: 1;
      transform: scale3d(1, 1, 1) translate(-50%);
    }
  }

  @keyframes bounceIn {
    from,
    20%,
    40%,
    60%,
    80%,
    to {
      animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    }

    0% {
      opacity: 0;
      transform: scale3d(0.3, 0.3, 0.3);
    }

    20% {
      transform: scale3d(1.1, 1.1, 1.1);
    }

    40% {
      transform: scale3d(0.9, 0.9, 0.9);
    }

    60% {
      opacity: 1;
      transform: scale3d(1.03, 1.03, 1.03);
    }

    80% {
      transform: scale3d(0.97, 0.97, 0.97);
    }

    to {
      opacity: 1;
      transform: scale3d(1, 1, 1);
    }
  }

  animation-duration: 1s;
  ${props =>
    (props.position === 'top-middle' || props.position === 'bottom-middle') &&
    `
    animation-name: ${props.open ? 'bounceInMiddle' : 'bounceOutMiddle'};
  `}

  ${props =>
    props.position !== 'top-middle' &&
    props.position !== 'bottom-middle' &&
    `
    animation-name: ${props.open ? 'bounceIn' : 'bounceOut'};
  `}

  @keyframes bounceOut {
    20% {
      transform: scale3d(0.9, 0.9, 0.9);
    }

    50%,
    55% {
      opacity: 1;
      transform: scale3d(1.1, 1.1, 1.1);
    }

    to {
      opacity: 0;
      transform: scale3d(0.3, 0.3, 0.3);
    }
  }

  @keyframes bounceOutMiddle {
    20% {
      transform: scale3d(0.9, 0.9, 0.9) translate(-50%);
    }

    50%,
    55% {
      opacity: 1;
      transform: scale3d(1.1, 1.1, 1.1) translate(-50%);
    }

    to {
      opacity: 0;
      transform: scale3d(0.3, 0.3, 0.3) translate(-50%);
    }
  }
`;

const ToastWrapper = styled.div`
  position: absolute;

  ${props =>
    props.position === 'top-left' &&
    `
    top: 20px;
    left: 20px;
  `}

  ${props =>
    props.position === 'top-right' &&
    `
    top: 20px;
    right: 20px;
  `}

  ${props =>
    props.position === 'top-middle' &&
    `
    top: 20px;
    left: 50%;
    transform: translate(-50%);
  `}

  ${props =>
    props.position === 'bottom-left' &&
    `
    bottom: 20px;
    left: 20px;
  `}

  ${props =>
    props.position === 'bottom-right' &&
    `
    bottom: 20px;
    right: 20px;
  `}

  ${props =>
    props.position === 'bottom-middle' &&
    `
    bottom: 20px;
    left: 50%;
    transform: translate(-50%);
  `}
`;

const TextContainer = styled.div`
  display: flex;
  flex-direction: column;
  margin-left: 20px;
`;

const Title = styled.span`
  font-family: ${props => props.theme.fonts.text};
  font-style: normal;
  font-weight: 700;
  font-size: 18px;
  color: ${props => props.color};
`;

const Description = styled.span`
  font-family: ${props => props.theme.fonts.text};
  font-style: normal;
  font-weight: 400;
  font-size: 16px;
  color: ${props => props.color};
`;

export const ToastContext = createContext();
export const useToast = () => useContext(ToastContext);

function generateUEID() {
  let first = (Math.random() * 46656) | 0;
  let second = (Math.random() * 46656) | 0;
  first = ('000' + first.toString(36)).slice(-3);
  second = ('000' + second.toString(36)).slice(-3);

  return first + second;
}

export const ToastProvider = props => {
  const [toasts, setToasts] = useState([]);
  const open = content => {
    setToasts(currentToasts => [...currentToasts, { id: generateUEID(), content }]);
  };
  const close = id => setToasts(currentToasts => currentToasts.filter(toast => toast.id !== id));
  const contextValue = useMemo(() => ({ open }), []);

  return (
    <ToastContext.Provider value={contextValue}>
      {props.children}
      {createPortal(
        <ToastWrapper position={toasts.length > 0 ? toasts[0].content.position : ''}>
          {toasts.map(toast => (
            <Toast key={toast.id} {...toast.content} close={() => close(toast.id)} />
          ))}
        </ToastWrapper>,
        document.body
      )}
    </ToastContext.Provider>
  );
};

ToastProvider.propTypes = {
  children: PropTypes.node
};

const Toast = props => {
  const { color, position, absolute, backgroundColor, title, description, progressBarColor, icon } = props;

  const [open, setOpen] = useState(true);
  const [startTime, setStartTime] = useState(null);
  const [timeout, setOurTimeout] = useState(null);
  const [remaining, setRemaining] = useState(null);

  const close = () => {
    setOpen(false);
    setTimeout(props.close, 1000);
  };

  const launchTimeout = (time = 4000) => {
    if (startTime === null) {
      setStartTime(Date.now());
    }
    let timeout = setTimeout(close, time);
    setOurTimeout(timeout);
    return timeout;
  };

  if (!timeout) {
    launchTimeout();
  }

  const onMouseHover = () => {
    if (remaining === null) {
      const elapsed = Date.now() - startTime;
      const remaining = 4000 - elapsed;
      setRemaining(remaining);
    }
    clearTimeout(timeout);
  };

  const onMouseLeave = () => {
    launchTimeout(remaining);
  };

  return (
    <Root
      absolute={absolute}
      position={position}
      onMouseOver={onMouseHover}
      onMouseEnter={onMouseHover}
      onMouseLeave={onMouseLeave}
      open={open}
      onClick={close}
      backgroundColor={backgroundColor}
    >
      <Icon strokeColor={color} name={icon} />
      <TextContainer>
        <Title color={color}>{title}</Title>
        <Description color={color}>{description}</Description>
      </TextContainer>
      <ProgressBar progressBarColor={progressBarColor} />
    </Root>
  );
};

Toast.propTypes = {
  absolute: PropTypes.bool,
  position: PropTypes.oneOf[('top-left', 'top-middle', 'top-right', 'bottom-left', 'bottom-middle', 'bottom-right')],
  backgroundColor: PropTypes.string,
  progressBarColor: PropTypes.string,
  color: PropTypes.string,
  title: PropTypes.string,
  description: PropTypes.string,
  icon: PropTypes.string,
  close: PropTypes.func
};

Toast.defaultProps = {
  absolute: false,
  position: 'top-middle',
  color: '#212121',
  title: '',
  description: '',
  backgroundColor: '#5cb85c',
  progressBarColor: '#ffce43',
  icon: null,
  close: null
};

export default Toast;
