import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import { ListCheckBox } from './ListCheckBox';

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

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

  it('defaults to false', () => {
    const { container } = render(<ListCheckBox />);

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

    expect(button?.classList.contains('context')).toBe(true);
  });

  it('sets its state to isChecked prop', () => {
    const { container } = render(<ListCheckBox isChecked={true} />);

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

    expect(button?.classList.contains('active')).toBe(true);
  });

  it(`raises the onCheckBoxToggled with the inverse of the 'isChecked' prop`, () => {
    const mockCheckedValue = true;
    const spy = vi.fn();
    const { container, rerender } = render(
      <ListCheckBox onCheckBoxToggled={spy} isChecked={mockCheckedValue} />,
    );
    const button = container.querySelector('button') as HTMLButtonElement;

    fireEvent.click(button);

    rerender(
      <ListCheckBox onCheckBoxToggled={spy} isChecked={!mockCheckedValue} />,
    );

    const buttonAfterRerender = container.querySelector(
      'button',
    ) as HTMLButtonElement;
    fireEvent.click(buttonAfterRerender);

    expect(spy).toHaveBeenCalledTimes(2);
    expect(spy).toHaveBeenNthCalledWith(1, !mockCheckedValue);
    expect(spy).toHaveBeenNthCalledWith(2, mockCheckedValue);
  });

  it('checkbox is enabled by default', () => {
    const spy = vi.fn();
    const { container } = render(<ListCheckBox onCheckBoxToggled={spy} />);
    const button = container.querySelector('button') as HTMLButtonElement;
    expect(button.disabled).toBe(false);
  });

  it('disable checkbox if isDisabled prop is true', () => {
    const spy = vi.fn();
    const { container } = render(
      <ListCheckBox onCheckBoxToggled={spy} isDisabled={true} />,
    );
    const button = container.querySelector('button') as HTMLButtonElement;
    expect(button.disabled).toBe(true);
    expect(button.classList.contains('disabled')).toBe(true);
  });

  it('disables container click event propagation', () => {
    const spy = vi.fn();
    const { container } = render(<ListCheckBox />);

    const containerDiv = container.querySelector('.container') as HTMLElement;

    const event = new MouseEvent('click', { bubbles: true });
    Object.defineProperty(event, 'stopPropagation', {
      value: spy,
      writable: true,
    });

    containerDiv.dispatchEvent(event);

    expect(spy).toHaveBeenCalledTimes(1);
  });

  it('allows the click event propagate when containerClickEvent is true', () => {
    const spy = vi.fn();
    const { container } = render(<ListCheckBox containerClickEvent={true} />);

    const containerDiv = container.querySelector('.container') as HTMLElement;

    const event = new MouseEvent('click', { bubbles: true });
    Object.defineProperty(event, 'stopPropagation', {
      value: spy,
      writable: true,
    });

    containerDiv.dispatchEvent(event);

    expect(spy).not.toHaveBeenCalled();
  });

  it('height and width props set Button height and width', () => {
    const mockHeight = '20px';
    const mockWidth = '20px';
    const { container } = render(
      <ListCheckBox height={mockHeight} width={mockWidth} />,
    );
    const button = container.querySelector('button') as HTMLButtonElement;
    expect(button.style.height).toBe(mockHeight);
    expect(button.style.width).toBe(mockWidth);
  });
});
