import { render, screen, fireEvent } from '@testing-library/react';
import { describe, test, expect, vi } from 'vitest';
import { userEvent } from '@testing-library/user-event';
import Tag from './Tag.js';

describe('Tag', () => {
  test('renders the tag with children text', () => {
    render(<Tag>Test Tag</Tag>);

    expect(screen.getByText('Test Tag')).toBeInTheDocument();
  });

  test('applies the correct CSS class', () => {
    render(<Tag>Test Tag</Tag>);

    // eslint-disable-next-line testing-library/no-node-access -- checking parent span class
    const tagElement = screen.getByText('Test Tag').closest('span');
    expect(tagElement).toHaveClass('tag');
  });

  test('does not render remove button when remove prop is not provided', () => {
    render(<Tag>Test Tag</Tag>);

    expect(screen.queryByRole('button')).not.toBeInTheDocument();
    expect(screen.queryByLabelText('Remove Test Tag')).not.toBeInTheDocument();
  });

  test('renders remove button when remove prop is provided', () => {
    const mockRemove = vi.fn();
    render(<Tag remove={mockRemove}>Test Tag</Tag>);

    const removeButton = screen.getByRole('button');
    expect(removeButton).toBeInTheDocument();
    expect(removeButton).toHaveClass('tag__remove');
  });

  test('renders remove button with correct aria-label', () => {
    const mockRemove = vi.fn();
    render(<Tag remove={mockRemove}>My Custom Tag</Tag>);

    expect(screen.getByLabelText('Remove My Custom Tag')).toBeInTheDocument();
  });

  test('renders X icon in remove button', () => {
    const mockRemove = vi.fn();
    render(<Tag remove={mockRemove}>Test Tag</Tag>);

    // The X icon from lucide-react should be present
    const removeButton = screen.getByRole('button');
    // eslint-disable-next-line testing-library/no-node-access -- checking SVG icon presence
    expect(removeButton.querySelector('svg')).toBeInTheDocument();
  });

  test('calls remove function when remove button is clicked', () => {
    const mockRemove = vi.fn();
    render(<Tag remove={mockRemove}>Test Tag</Tag>);

    const removeButton = screen.getByRole('button');
    fireEvent.click(removeButton);

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

  test('passes the mouse event to remove function', () => {
    const mockRemove = vi.fn();
    render(<Tag remove={mockRemove}>Test Tag</Tag>);

    const removeButton = screen.getByRole('button');
    fireEvent.click(removeButton);

    expect(mockRemove).toHaveBeenCalledWith(expect.any(Object));
  });

  test('remove button has correct type attribute', () => {
    const mockRemove = vi.fn();
    render(<Tag remove={mockRemove}>Test Tag</Tag>);

    const removeButton = screen.getByRole('button');
    expect(removeButton).toHaveAttribute('type', 'button');
  });

  test('handles special characters in tag text for aria-label', () => {
    const mockRemove = vi.fn();
    const tagText = 'Tag with "quotes" & symbols';
    render(<Tag remove={mockRemove}>{tagText}</Tag>);

    expect(screen.getByLabelText(`Remove ${tagText}`)).toBeInTheDocument();
  });

  test('can handle multiple remove button clicks', () => {
    const mockRemove = vi.fn();
    render(<Tag remove={mockRemove}>Test Tag</Tag>);

    const removeButton = screen.getByRole('button');
    fireEvent.click(removeButton);
    fireEvent.click(removeButton);
    fireEvent.click(removeButton);

    expect(mockRemove).toHaveBeenCalledTimes(3);
  });

  describe('keyboard accessibility', () => {
    test('remove button can be focused', () => {
      const mockRemove = vi.fn();
      render(<Tag remove={mockRemove}>Test Tag</Tag>);

      const removeButton = screen.getByRole('button');
      removeButton.focus();

      expect(removeButton).toHaveFocus();
    });

    test('calls remove function when Enter is pressed on remove button', async () => {
      const user = userEvent.setup();
      const mockRemove = vi.fn();
      render(<Tag remove={mockRemove}>Test Tag</Tag>);
      const removeButton = screen.getByLabelText('Remove Test Tag');
      removeButton.focus();
      await user.keyboard('{Enter}');

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

    test('calls remove function when Space is pressed on remove button', async () => {
      const user = userEvent.setup();
      const mockRemove = vi.fn();
      render(<Tag remove={mockRemove}>Test Tag</Tag>);

      const removeButton = screen.getByLabelText('Remove Test Tag');
      removeButton.focus();
      await user.keyboard(' ');

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