import { Info, Alert, Cross, Check, ClockBorderless } from '@transferwise/icons';
import { clsx } from 'clsx';
import { useIntl } from 'react-intl';
import { PropsWithChildren } from 'react';

import SentimentSurface from '../sentimentSurface';
import { SizeSmall, SizeMedium, SizeLarge, Sentiment, Size, Breakpoint, Status } from '../common';
import Circle, { CircleProps } from '../common/circle';
import { useMedia } from '../common/hooks/useMedia';

import messages from './StatusIcon.messages';

/**
 * @deprecated use `16 | 24 | 32 | 40 | 48 | 56 | 72` component instead
 */
type LegacySizes = SizeSmall | SizeMedium | SizeLarge;

export type StatusIconSentiment = Sentiment | Status.PENDING;

export type StatusIconProps = {
  sentiment?: `${StatusIconSentiment}`;
  size?: LegacySizes | 16 | 24 | 32 | 40 | 48 | 56 | 72;
  /**
   * Override for the sentiment's-derived, default, accessible
   * name announced by the screen readers. <br />
   * Using `null` will render the icon purely presentational.
   * */
  iconLabel?: string | null;
};

const mapLegacySize = {
  [String(Size.SMALL)]: 16,
  [String(Size.MEDIUM)]: 40,
  [String(Size.LARGE)]: 48,
} satisfies Record<string, CircleProps['size']>;

const StatusIcon = ({ sentiment = 'neutral', size: sizeProp = 40, iconLabel }: StatusIconProps) => {
  const intl = useIntl();

  const iconMetaBySentiment: Record<
    `${Sentiment}` | Status.PENDING,
    {
      Icon: React.ElementType;
      defaultIconLabel: string;
    }
  > = {
    [Sentiment.NEGATIVE]: {
      Icon: Cross,
      defaultIconLabel: intl.formatMessage(messages.errorLabel),
    },
    [Sentiment.POSITIVE]: {
      Icon: Check,
      defaultIconLabel: intl.formatMessage(messages.successLabel),
    },
    [Sentiment.WARNING]: {
      Icon: Alert,
      defaultIconLabel: intl.formatMessage(messages.warningLabel),
    },
    [Status.PENDING]: {
      Icon: ClockBorderless,
      defaultIconLabel: intl.formatMessage(messages.pendingLabel),
    },
    [Sentiment.NEUTRAL]: {
      Icon: Info,
      defaultIconLabel: intl.formatMessage(messages.informationLabel),
    },
    // deprecated
    [Sentiment.ERROR]: {
      Icon: Cross,
      defaultIconLabel: intl.formatMessage(messages.errorLabel),
    },
    [Sentiment.INFO]: {
      Icon: Info,
      defaultIconLabel: intl.formatMessage(messages.informationLabel),
    },
    [Sentiment.SUCCESS]: {
      Icon: Check,
      defaultIconLabel: intl.formatMessage(messages.successLabel),
    },
  };
  const { Icon, defaultIconLabel } = iconMetaBySentiment[sentiment];

  const iconColor = sentiment === 'warning' || sentiment === 'pending' ? 'dark' : 'light';
  const isTinyViewport = useMedia(`(max-width: ${Breakpoint.ZOOM_400}px)`);
  const size = mapLegacySize[sizeProp] ?? sizeProp;
  // eslint-disable-next-line react/no-unstable-nested-components
  const SentimentSurfaceSetting = (props: PropsWithChildren<Pick<CircleProps, 'className'>>) => (
    <SentimentSurface
      as="span"
      // @ts-expect-error sentiment and SentimentSurface types mismatch
      sentiment={
        sentiment === 'positive' ? 'success' : sentiment === 'pending' ? 'warning' : sentiment
      }
      {...props}
    />
  );
  return (
    <Circle
      as={SentimentSurfaceSetting}
      size={isTinyViewport && size < 40 ? 32 : size}
      data-testid="status-icon"
      className={clsx('status-circle', sentiment)}
    >
      <Icon
        className={clsx('status-icon', iconColor)}
        title={iconLabel === null ? undefined : iconLabel || defaultIconLabel}
      />
    </Circle>
  );
};

export default StatusIcon;
