import * as React from 'react';
import {
  render,
  screen
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as ButtonBase from '@tesseract-design/web-base-button';
import * as CheckControlBase from '@tesseract-design/web-base-checkcontrol';
import { vi } from 'vitest';
import { RadioButton } from '.';

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

describe('RadioButton', () => {
  it('renders a radio button', () => {
    render(
      <RadioButton />
    );
    const checkbox = screen.getByRole('radio');
    expect(checkbox).toBeInTheDocument();
  });

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

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

  it('handles click events', () => {
    const onClick = vi.fn().mockImplementationOnce((e) => { e.preventDefault(); });
    render(
      <RadioButton
        onClick={onClick}
      />
    );
    const button: HTMLInputElement = screen.getByRole('radio');
    userEvent.click(button);
    expect(onClick).toBeCalled();
  });

  it('renders a compact button', () => {
    render(
      <RadioButton
        compact
      />
    );

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

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

  describe.each(Object.values(ButtonBase.ButtonSize))('on %s size', (size) => {
    it('renders button styles', () => {
      render(
        <RadioButton
          size={size}
        />
      );

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

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

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

  it.each(Object.values(ButtonBase.ButtonVariant))('renders a button with variant %s', (variant) => {
    render(
      <RadioButton
        variant={variant}
      />
    );

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

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

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

  it('renders a block button', () => {
    render(
      <RadioButton
        block
      />
    );

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

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

    expect(CheckControlBase.ClickAreaWrapper).toBeCalledWith(expect.objectContaining({
      block: true,
    }));
  });

  it('renders children', () => {
    render(
      <RadioButton>
        Foo
      </RadioButton>
    );

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

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

  it('handles change events', () => {
    const onChange = vi.fn().mockImplementationOnce((e) => { e.preventDefault(); })
    render(
      <RadioButton
        onChange={onChange}
      />
    );
    const radio: HTMLInputElement = screen.getByRole('radio');
    userEvent.click(radio);
    expect(onChange).toBeCalled();
  });
});
