import { mockMatchMedia, render, screen } from '../../test-utils';
import { InlinePrompt, InlinePromptProps } from './InlinePrompt';
import { Sentiment } from '../../common';

mockMatchMedia();

const MEDIA = <span data-testid="custom-media">Custom Media</span>;

describe('InlinePrompt', () => {
  const defaultProps: InlinePromptProps = {
    children: 'Prompt message',
  };

  it('renders children', () => {
    render(<InlinePrompt {...defaultProps}>Hello world</InlinePrompt>);
    expect(screen.getByText('Hello world')).toBeInTheDocument();
  });

  it('renders with GiftBox icon as default for `proposition` sentiment', () => {
    render(<InlinePrompt {...defaultProps} sentiment="proposition" />);
    expect(screen.getByText('Prompt message')).toBeInTheDocument();
    expect(screen.getByTestId('gift-box-icon')).toBeInTheDocument();
  });

  [
    { sentiment: Sentiment.NEGATIVE as const, acceptsMedia: false, statusIconLabel: 'Error:' },
    { sentiment: Sentiment.WARNING as const, acceptsMedia: false, statusIconLabel: 'Warning:' },
    { sentiment: Sentiment.NEUTRAL as const, acceptsMedia: false, statusIconLabel: 'Information:' },
    { sentiment: Sentiment.POSITIVE as const, acceptsMedia: true, statusIconLabel: 'Success:' },
    { sentiment: 'proposition' as const, acceptsMedia: true, statusIconLabel: '' },
  ].forEach(({ sentiment, statusIconLabel, acceptsMedia }) => {
    describe(sentiment, () => {
      it('should apply correct styles', () => {
        render(<InlinePrompt {...defaultProps} sentiment={sentiment} />);
        expect(screen.getByText('Prompt message').parentElement).toHaveClass(
          `wds-inline-prompt--${sentiment}`,
        );
      });

      if (statusIconLabel) {
        it('should render StatusIcon', () => {
          render(<InlinePrompt {...defaultProps} sentiment={sentiment} />);
          expect(screen.getByLabelText(statusIconLabel)).toBeInTheDocument();
        });
      }

      describe('muted state', () => {
        it('should render icon and apply css', () => {
          render(<InlinePrompt {...defaultProps} muted sentiment={sentiment} />);
          expect(screen.getByText('Prompt message').parentElement).toHaveClass(
            'wds-inline-prompt--muted',
          );
          expect(screen.getByTestId('InlinePrompt_Muted')).toBeInTheDocument();
        });

        it('should trump `media`', () => {
          render(<InlinePrompt {...defaultProps} muted sentiment={sentiment} media={MEDIA} />);
          expect(screen.getByTestId('InlinePrompt_Muted')).toBeInTheDocument();
          expect(screen.queryByTestId('custom-media')).not.toBeInTheDocument();
        });
      });

      describe('loading state', () => {
        it('should render icon and apply css', () => {
          render(<InlinePrompt {...defaultProps} sentiment={sentiment} loading />);
          expect(screen.getByText('Prompt message').parentElement).toHaveClass(
            'wds-inline-prompt--loading',
          );
          expect(screen.getByTestId('InlinePrompt_ProcessIndicator')).toBeInTheDocument();
        });

        it('should trump `media`', () => {
          render(<InlinePrompt {...defaultProps} sentiment={sentiment} loading media={MEDIA} />);
          expect(screen.getByTestId('InlinePrompt_ProcessIndicator')).toBeInTheDocument();
          expect(screen.queryByTestId('custom-media')).not.toBeInTheDocument();
        });
      });

      describe('custom media', () => {
        if (acceptsMedia) {
          it('should respect `media`', () => {
            render(<InlinePrompt {...defaultProps} sentiment={sentiment} media={MEDIA} />);
            expect(screen.getByTestId('custom-media')).toBeInTheDocument();
          });
        } else {
          it('should ignore `media`', () => {
            render(<InlinePrompt {...defaultProps} sentiment={sentiment} media={MEDIA} />);
            expect(screen.getByLabelText(statusIconLabel)).toBeInTheDocument();
            expect(screen.queryByTestId('custom-media')).not.toBeInTheDocument();
          });
        }
      });

      describe('iconLabel', () => {
        const iconLabel = 'Custom icon label';

        if (!statusIconLabel) {
          it('should not have accessible name for the icon', () => {
            const { container } = render(<InlinePrompt {...defaultProps} sentiment={sentiment} />);
            expect(container.querySelector('svg')).not.toHaveAccessibleName();
          });
        } else {
          it('should use default aria label', () => {
            render(<InlinePrompt {...defaultProps} sentiment={sentiment} />);
            expect(screen.getByLabelText(statusIconLabel)).toBeInTheDocument();
          });
        }

        it('should allow for customisation of aria label', () => {
          render(<InlinePrompt {...defaultProps} sentiment={sentiment} iconLabel={iconLabel} />);
          expect(screen.getByLabelText(iconLabel)).toBeInTheDocument();
        });

        it('should retain custom label while muted', () => {
          render(
            <InlinePrompt {...defaultProps} sentiment={sentiment} iconLabel={iconLabel} muted />,
          );
          expect(screen.getByLabelText(iconLabel)).toBeInTheDocument();
        });
      });
    });
  });

  it('applies custom className, id, and data-testid', () => {
    render(
      <InlinePrompt
        {...defaultProps}
        className="custom-class"
        id="custom-id"
        data-testid="custom-test"
      />,
    );
    const el = screen.getByTestId('custom-test');
    expect(el).toHaveClass('custom-class');
    expect(el).toHaveAttribute('id', 'custom-id');
  });

  describe('SentimentSurface integration', () => {
    it('maps positive sentiment to success for SentimentSurface', () => {
      render(
        <InlinePrompt {...defaultProps} sentiment={Sentiment.POSITIVE} data-testid="prompt" />,
      );
      const el = screen.getByTestId('prompt');
      // The component should have both the original class and the SentimentSurface class
      expect(el).toHaveClass('wds-inline-prompt--positive');
      expect(el).toHaveClass('wds-sentiment-surface');
    });

    it('passes through other sentiments unchanged', () => {
      render(
        <InlinePrompt {...defaultProps} sentiment={Sentiment.NEGATIVE} data-testid="prompt" />,
      );
      const el = screen.getByTestId('prompt');
      expect(el).toHaveClass('wds-inline-prompt--negative');
      expect(el).toHaveClass('wds-sentiment-surface');
    });
  });
});
