import { Sentiment, Size, Status } from '../common';
import { render, cleanup, screen, mockMatchMedia } from '../test-utils';

import StatusIcon, { type StatusIconProps } from '.';
import { StatusIconSentiment } from './StatusIcon';

mockMatchMedia();

describe('StatusIcon', () => {
  const renderStatusIcon = (props?: StatusIconProps) => {
    return render(
      <StatusIcon
        sentiment={props?.sentiment || Sentiment.NEUTRAL}
        size={props?.size || Size.MEDIUM}
        iconLabel={props?.iconLabel}
      />,
    );
  };

  afterEach(cleanup);

  it('renders the status icon without any props', () => {
    renderStatusIcon();

    expect(screen.getByTestId('status-icon')).toHaveClass('neutral');
    expect(screen.getByTestId('status-icon')).toHaveClass('status-circle');
  });

  it.each([
    [Sentiment.NEGATIVE, Sentiment.NEGATIVE],
    [Sentiment.NEUTRAL, Sentiment.NEUTRAL],
    [Sentiment.PENDING, Sentiment.PENDING],
    [Status.PENDING, Status.PENDING],
    [Sentiment.POSITIVE, Sentiment.POSITIVE],
    [Sentiment.WARNING, Sentiment.WARNING],
  ])(
    "if prop 'sentiment' equals '%s' is passed, renders the status icon with class '%s'",
    (sentiment: Sentiment | Status, expectedClass: Sentiment | Status) => {
      renderStatusIcon({ sentiment: sentiment as StatusIconSentiment });

      expect(screen.getByTestId('status-icon')).toHaveClass(expectedClass);
    },
  );

  it.each([
    [Sentiment.WARNING, 'alert-icon'],
    [Sentiment.PENDING, 'clock-borderless-icon'],
    [Status.PENDING, 'clock-borderless-icon'],
    [Sentiment.POSITIVE, 'check-icon'],
    [Sentiment.NEGATIVE, 'cross-icon'],
    [Sentiment.NEUTRAL, 'info-icon'],
  ])(
    "renders the correct icon for '%s' sentiment",
    (sentiment: Sentiment | Status, expectedIconTestId: string) => {
      renderStatusIcon({ sentiment: sentiment as StatusIconSentiment });

      const icon = screen.getByTestId(expectedIconTestId);
      expect(icon).toBeInTheDocument();
      expect(icon).toHaveClass('status-icon');
    },
  );

  describe('accessible name', () => {
    it.each([
      ['Error', Sentiment.NEGATIVE],
      ['Success', Sentiment.POSITIVE],
      ['Warning', Sentiment.WARNING],
      ['Pending', Status.PENDING],
      ['Information', Sentiment.NEUTRAL],
      ['Error', Sentiment.ERROR],
      ['Information', Sentiment.INFO],
      ['Success', Sentiment.SUCCESS],
    ])(
      "should set '%s' as an accessible name for the '%s' sentiment",
      (label: string, sentiment: Sentiment | Status) => {
        renderStatusIcon({ sentiment: sentiment as StatusIconSentiment });

        expect(screen.getByLabelText(`${label}:`)).toBeInTheDocument();
      },
    );

    it('should allow for `iconLabel` overrides', () => {
      const iconLabel = 'Custom label';
      renderStatusIcon({ sentiment: Sentiment.NEGATIVE, iconLabel });

      expect(screen.getByLabelText(iconLabel)).toBeInTheDocument();
      expect(screen.queryByLabelText(`Error:`)).not.toBeInTheDocument();
    });

    it('should allow for `iconLabel` to be `null` to keep the icon presentational', () => {
      const iconLabel = null;
      renderStatusIcon({ sentiment: Sentiment.NEGATIVE, iconLabel });

      expect(screen.queryByRole(`graphics-symbol`)).not.toBeInTheDocument();
      expect(screen.queryByLabelText(`Error:`)).not.toBeInTheDocument();
    });
  });
});
