import * as React from 'react';
import {
  render,
  screen,
} from '@testing-library/react';
import '@testing-library/jest-dom';
import {
  ActionButton,
  ActionButtonType,
} from '.';
import userEvent from '@testing-library/user-event';
import * as ButtonBase from '@tesseract-design/web-base-button';

jest.mock('@tesseract-design/web-base-button');

describe('ActionButton', () => {
  it('should render a button', () => {
    render(
      <ActionButton />
    );
    const button: HTMLButtonElement = screen.getByRole('button');
    expect(button).toBeInTheDocument();
    expect(button).toHaveProperty('type', 'button');
  });

  it('should render a subtext', () => {
    render(
      <ActionButton
        subtext="subtext"
      />
    );
    const subtext: HTMLElement = screen.getByTestId('subtext');
    expect(subtext).toBeInTheDocument();
  });

  it('should render a badge', () => {
    render(
      <ActionButton
        badge="badge"
      />
    );
    const badge: HTMLElement = screen.getByTestId('badge');
    expect(badge).toBeInTheDocument();
  });

  it('should render as a menu item', () => {
    render(
      <ActionButton
        menuItem
      />
    );
    const menuItemIndicator: HTMLElement = screen.getByTestId('menuItemIndicator');
    expect(menuItemIndicator).toBeInTheDocument();
  });

  it('should handle click events', () => {
    const onClick = jest.fn();
    render(
      <ActionButton
        onClick={onClick}
      />
    );
    const button: HTMLButtonElement = screen.getByRole('button');
    userEvent.click(button);
    expect(onClick).toBeCalled();
  });

  it('should render a compact button', () => {
    render(
      <ActionButton
        compact
      />
    );

    expect(ButtonBase.Button).toBeCalledWith(expect.objectContaining({
      compact: true,
    }));

    expect(ButtonBase.Label).toBeCalledWith(expect.objectContaining({
      compact: true,
    }));
  });

  describe.each([
    ButtonBase.ButtonSize.SMALL,
    ButtonBase.ButtonSize.MEDIUM,
    ButtonBase.ButtonSize.LARGE,
  ])('on %s size', (size) => {
    it('should render button styles', () => {
      render(
        <ActionButton
          size={size}
        />
      );

      expect(ButtonBase.Button).toBeCalledWith(expect.objectContaining({
        size,
      }));
    });

    it('should render badge styles', () => {
      render(
        <ActionButton
          size={size}
          badge="badge"
        />
      );

      expect(ButtonBase.BadgeContainer).toBeCalledWith(expect.objectContaining({
        size,
      }));
    });

    it('should render indicator styles', () => {
      render(
        <ActionButton
          size={size}
          menuItem
        />
      );

      expect(ButtonBase.IndicatorWrapper).toBeCalledWith(expect.objectContaining({
        size,
      }));
    });
  });

  it.each([
    ButtonBase.ButtonVariant.OUTLINE,
    ButtonBase.ButtonVariant.FILLED,
  ])('should render a button with variant %s', (variant) => {
    render(
      <ActionButton
        variant={variant}
      />
    );

    expect(ButtonBase.Button).toBeCalledWith(expect.objectContaining({
      variant,
    }));
  });

  it('should render a bordered button', () => {
    render(
      <ActionButton
        border
      />
    );

    expect(ButtonBase.Border).toBeCalledWith(expect.objectContaining({
      border: true,
    }));
  });

  it('should render a block button', () => {
    render(
      <ActionButton
        block
      />
    );

    expect(ButtonBase.Border).toBeCalledWith(expect.objectContaining({
      block: true,
    }));
  });

  it('should render children', () => {
    render(
      <ActionButton>
        Foo
      </ActionButton>
    );

    const children: HTMLElement = screen.getByTestId('children');
    expect(children).toHaveTextContent('Foo');
  });

  it.each([
    ActionButtonType.BUTTON,
    ActionButtonType.RESET,
    ActionButtonType.SUBMIT,
  ])('should render a button with type %s', (buttonType) => {
    render(
      <ActionButton
        type={buttonType}
      />
    );
    const button: HTMLButtonElement = screen.getByRole('button');
    expect(button).toHaveProperty('type', buttonType);
  });

  it('should render a disabled button', () => {
    render(
      <ActionButton
        disabled
      />
    );
    const button: HTMLButtonElement = screen.getByRole('button');
    expect(button).toBeDisabled();
  });
});
