import { render, screen } from '@testing-library/react';
import React from 'react';
import { describe, expect, it } from 'vitest';
import { IconName } from '../Icons';
import { Message, MessageProps } from './Message';

const defaultProps: MessageProps = {
  title: 'test-message',
};

describe('Message', () => {
  it('renders the component without crashing', () => {
    const { container } = render(<Message {...defaultProps} />);

    expect(container).toBeTruthy();
  });

  it(`renders a message`, () => {
    render(<Message {...defaultProps} />);

    const message = screen.getByTestId('message-title');

    expect(message.textContent).toBe(defaultProps.title);
  });

  it('allows an optional class to be passed in', () => {
    const mockClass = 'test-class';
    const { container } = render(
      <Message {...defaultProps} className={mockClass} />,
    );

    const messageContainer = container.querySelector('.message-container');

    expect(messageContainer?.classList.contains(mockClass)).toBe(true);
  });

  describe('message types', () => {
    it.each([
      [undefined, IconName.Error, 'hasError'],
      ['error', IconName.Error, 'hasError'],
      ['info', IconName.Info, 'hasInfo'],
      ['success', IconName.Success, 'hasSuccess'],
      ['warning', IconName.Warning, 'hasWarning'],
    ])('message type styling', (type, icon, className) => {
      const { container } = render(
        <Message {...defaultProps} type={type as MessageProps['type']} />,
      );

      const messageElement = screen.getByTestId('message');
      const messageContainer = container.querySelector('.message-container');

      expect(messageElement.getAttribute('data-test-type')).toBe(
        type || 'error',
      );
      expect(messageContainer?.classList.contains(className)).toBe(true);
    });
  });

  describe('header', () => {
    it(`renders a header component if set`, () => {
      const mockHeader: JSX.Element = <div>test</div>;

      const { container, rerender } = render(<Message {...defaultProps} />);

      let header = container.querySelector('.header');

      expect(header).toBeNull();

      rerender(<Message {...defaultProps} header={mockHeader} />);

      header = container.querySelector('.header');

      expect(header).toBeTruthy();
    });
  });

  describe('message body', () => {
    it(`does not render a body if component has no children`, () => {
      const { container } = render(<Message {...defaultProps} />);

      const body = container.querySelector('.body');

      expect(body).toBeNull();
    });

    it(`does not render a body if component has children but 'isBodyOpen' is not true`, () => {
      const { container } = render(<Message {...defaultProps}>Test</Message>);

      const body = container.querySelector('.body');

      expect(body).toBeNull();
    });

    it(`renders a body if component has children and 'isBodyOpen' is true`, () => {
      const { container, rerender } = render(
        <Message {...defaultProps}>Test</Message>,
      );

      let body = container.querySelector('.body');

      expect(body).toBeNull();

      rerender(
        <Message {...defaultProps} isBodyOpen={true}>
          Test
        </Message>,
      );

      body = container.querySelector('.body');

      expect(body).toBeTruthy();
    });

    it(`sets body position to 'absolute' by default and allows it to be removed`, () => {
      const { container, rerender } = render(
        <Message {...defaultProps} isBodyOpen={true}>
          Test
        </Message>,
      );

      let body = container.querySelector('.body');

      expect(body?.classList.contains('absolute')).toBe(true);

      rerender(
        <Message
          {...defaultProps}
          isBodyOpen={true}
          isBodyPositionAbsolute={false}
        >
          Test
        </Message>,
      );

      body = container.querySelector('.body');

      expect(body?.classList.contains('absolute')).toBe(false);
    });
  });
});
