import React, { memo } from 'react';
import styled, { css, keyframes } from 'styled-components';

import type { ReactElement } from 'react';
import type { ToastItem, ToastType } from '@redocly/theme/core/types';

import { CheckmarkFilledIcon } from '@redocly/theme/icons/CheckmarkFilledIcon/CheckmarkFilledIcon';
import { CircleDashIcon } from '@redocly/theme/icons/CircleDashIcon/CircleDashIcon';
import { CloseIcon } from '@redocly/theme/icons/CloseIcon/CloseIcon';
import { ErrorFilledIcon } from '@redocly/theme/icons/ErrorFilledIcon/ErrorFilledIcon';
import { InformationFilledIcon } from '@redocly/theme/icons/InformationFilledIcon/InformationFilledIcon';
import { WarningFilledIcon } from '@redocly/theme/icons/WarningFilledIcon/WarningFilledIcon';
import { useToastLogic } from '@redocly/theme/core/hooks';
import { Button } from '@redocly/theme/components/Button/Button';
import { TOAST_SLIDE_DURATION_MS } from '@redocly/theme/core/constants/toast';

function renderToastIcon(type: ToastType): ReactElement {
  switch (type) {
    case 'success':
      return <CheckmarkFilledIcon size="--toast-icon-size" color="--toast-icon-color-success" />;
    case 'warning':
      return <WarningFilledIcon size="--toast-icon-size" color="--toast-icon-color-warning" />;
    case 'error':
      return <ErrorFilledIcon size="--toast-icon-size" color="--toast-icon-color-error" />;
    case 'loading':
      return <CircleDashIcon size="--toast-icon-size" color="--toast-icon-color-loading" />;
    case 'info':
    default:
      return <InformationFilledIcon size="--toast-icon-size" color="--toast-icon-color-info" />;
  }
}

function renderDismissButton(onClick: () => void): ReactElement {
  return (
    <CloseButton
      aria-label="Dismiss notification"
      title="Dismiss notification"
      icon={
        <CloseIcon size="--toast-close-button-icon-size" color="--toast-close-button-icon-color" />
      }
      onClick={onClick}
    />
  );
}

export interface ToastComponentProps {
  toast: ToastItem;
  onDismiss: (id: string) => void;
  stackIndex: number;
  stackZIndex?: number;
  className?: string;
}

function ToastComponent({
  toast,
  onDismiss,
  stackIndex,
  stackZIndex = 1,
  className,
}: ToastComponentProps): ReactElement {
  const {
    wrapperRef,
    hasDetails,
    dismissToast,
    handleMouseEnter,
    handleMouseLeave,
    ariaRole,
    ariaLive,
  } = useToastLogic({
    toast,
    onDismiss,
    stackIndex,
  });

  const icon = renderToastIcon(toast.type);
  const content = !hasDetails ? (
    <SimpleToastSurface $isExiting={toast.isExiting} aria-live={ariaLive} role={ariaRole}>
      <ContentWrapper>
        <IconWrapper>{icon}</IconWrapper>
        <SimpleContent>
          <SimpleText>{toast.title}</SimpleText>
        </SimpleContent>
      </ContentWrapper>
      {renderDismissButton(dismissToast)}
    </SimpleToastSurface>
  ) : (
    <DetailedToastSurface $isExiting={toast.isExiting} aria-live={ariaLive} role={ariaRole}>
      <ContentWrapper>
        <IconWrapper>{icon}</IconWrapper>
        <Body>
          <TitleRow>
            <TitleText>{toast.title}</TitleText>
            {renderDismissButton(dismissToast)}
          </TitleRow>
          {toast.description ? (
            <DescriptionRow>
              <DescriptionText>{toast.description}</DescriptionText>
            </DescriptionRow>
          ) : null}
        </Body>
      </ContentWrapper>
    </DetailedToastSurface>
  );

  return (
    <ToastWrapper
      ref={wrapperRef}
      $stackZIndex={stackZIndex}
      className={className}
      data-component-name="Toast/Toast"
      data-testid={`toast-${toast.type}`}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      {content}
    </ToastWrapper>
  );
}

export const Toast = memo(ToastComponent);

const slideIn = keyframes`
  from {
    opacity: 0;
    transform: translateX(100%);
  }

  to {
    opacity: 1;
    transform: translateX(0);
  }
`;

const slideOut = keyframes`
  from {
    opacity: 1;
    transform: translateX(0);
  }

  to {
    opacity: 0;
    transform: translateX(100%);
  }
`;

export const spin = keyframes`
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
`;

const ToastWrapper = styled.div<{ $stackZIndex: number }>`
  position: relative;
  z-index: ${({ $stackZIndex }) => $stackZIndex};
  width: 100%;
  pointer-events: auto;
  will-change: transform;
`;

const ToastSurface = styled.div<{ $isExiting: boolean }>`
  display: flex;
  align-items: flex-start;
  width: 100%;
  min-width: var(--toast-min-width);
  max-width: var(--toast-max-width);
  background-color: var(--toast-bg-color);
  border: var(--toast-border);
  border-radius: var(--toast-border-radius);
  box-shadow: var(--toast-box-shadow);
  color: var(--toast-text-color);
  font-family: var(--toast-font-family);
  animation: ${({ $isExiting }) =>
    $isExiting
      ? css`
          ${slideOut} ${TOAST_SLIDE_DURATION_MS}ms ease-in forwards
        `
      : css`
          ${slideIn} ${TOAST_SLIDE_DURATION_MS}ms ease-out
        `};

  @media (max-width: 480px) {
    min-width: 0;
    max-width: none;
  }
`;

const SimpleToastSurface = styled(ToastSurface)`
  gap: var(--toast-simple-gap);
  padding: var(--toast-simple-padding);
`;

const DetailedToastSurface = styled(ToastSurface)`
  padding: var(--toast-detailed-padding);
`;

const ContentWrapper = styled.div`
  display: flex;
  flex: 1 1 auto;
  gap: var(--toast-content-gap);
  min-width: 0;
`;

const IconWrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--toast-icon-size);
  min-width: var(--toast-icon-size);
  height: var(--toast-icon-line-height);

  ${CircleDashIcon} {
    animation: ${spin} var(--toast-loading-animation-duration) linear infinite;
  }
`;

const flexItemStyles = css`
  flex: 1 1 auto;
  min-width: 0;
`;

const SimpleContent = styled.div`
  ${flexItemStyles}
`;

const Body = styled.div`
  display: flex;
  ${flexItemStyles}
  flex-direction: column;
`;

const TitleRow = styled.div`
  display: flex;
  align-items: center;
  gap: var(--toast-title-gap);
  min-width: 0;
`;

const DescriptionRow = styled.div`
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--toast-description-gap);
  min-width: 0;
`;

const textStyles = css`
  margin: 0;
  font-size: var(--toast-text-font-size);
  line-height: var(--toast-text-line-height);
  color: var(--toast-text-color);
  overflow-wrap: anywhere;
`;

const TitleText = styled.p`
  ${textStyles}
  ${flexItemStyles}
  font-weight: var(--toast-title-font-weight);
`;

const SimpleText = styled.p`
  ${textStyles}
  font-weight: var(--toast-body-font-weight);
`;

const DescriptionText = styled.p`
  ${textStyles}
  ${flexItemStyles}
  font-weight: var(--toast-body-font-weight);
`;

const CloseButton = styled(Button).attrs({
  variant: 'ghost',
  size: 'small',
})`
  flex: 0 0 auto;
  min-height: unset;
  margin: 0;
  padding: var(--toast-close-button-padding);
  color: var(--toast-close-button-icon-color);

  &:hover,
  &:focus-visible {
    border: none;
  }
`;
