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

const mockLabel = 'mockLabel';

const mockOptions = [
  {
    value: '1',
    label: 'One',
  },
  {
    value: '2',
    label: 'Two',
  },
  {
    value: '3',
    label: 'Three',
  },
];

describe('Select', () => {
  it('renders the component without crashing', () => {
    const { container } = render(<Select name="test-name" options={[]} />);

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

  it('displays a label', () => {
    const { container } = render(
      <Select name="test-name" label={mockLabel} options={[]} />,
    );

    const label = container.querySelector('[data-test-id="form-field-label"]');

    expect(label?.textContent).toBe(mockLabel);
  });

  it('the given value must be filled in input', () => {
    const { container } = render(
      <Select name={'test-name'} options={mockOptions} value="2" />,
    );

    const input = container.querySelector(
      '[role="combobox"]',
    ) as HTMLInputElement;

    expect(input.value).toEqual(mockOptions[1].label);
  });

  it('the popper must be rendered on input click', () => {
    const { container } = render(
      <Select name={'test-name'} options={mockOptions} value="2" />,
    );
    const input = container.querySelector('[role="combobox"]') as HTMLElement;
    fireEvent.mouseDown(input);

    const popper = document.querySelector('[role="tooltip"]');
    expect(popper).not.toBeNull();
  });

  it('raises change, blur, and focus events', () => {
    const changeSpy = vi.fn();
    const blurSpy = vi.fn();
    const focusSpy = vi.fn();
    const { container } = render(
      <Select
        name={'test-name'}
        onChange={changeSpy}
        onBlur={blurSpy}
        onFocus={focusSpy}
        options={mockOptions}
      />,
    );

    const input = container.querySelector('[role="combobox"]') as HTMLElement;
    fireEvent.mouseDown(input);
    const firstOption = document.querySelector('[role="option"]');
    firstOption?.dispatchEvent(new Event('click', { bubbles: true }));

    expect(changeSpy).toHaveBeenCalledTimes(1);

    fireEvent.blur(input);
    expect(blurSpy).toHaveBeenCalledTimes(1);

    fireEvent.focus(input);
    expect(focusSpy).toHaveBeenCalledTimes(1);
  });

  it('applies error styling and renders error message when an error is passed', () => {
    const mockErrorMessage = 'test-error-message';
    const { container } = render(
      <Select name={'test-name'} error={mockErrorMessage} options={[]} />,
    );

    const errorMsg = container.querySelector(
      '[data-test-id="form-field-error"]',
    );
    const input = container.querySelector('[role="combobox"]');

    expect(errorMsg?.textContent).toBe(mockErrorMessage);
    expect(input?.classList.contains('hasError')).toBe(true);
  });
});
