import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import userEvent from '@testing-library/user-event';
import { List, ListItem } from './List';

describe('List Component', () => {
  const mockItems: ListItem[] = [
    {
      id: '1',
      content: 'Item 1',
      onClick: vi.fn(),
    },
    {
      id: '2',
      content: 'Item 2',
      actions: <button>Action</button>,
    },
    {
      id: '3',
      content: 'Item 3',
    },
  ];

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders list items', () => {
    render(<List items={mockItems} />);

    expect(screen.getByText('Item 1')).toBeInTheDocument();
    expect(screen.getByText('Item 2')).toBeInTheDocument();
    expect(screen.getByText('Item 3')).toBeInTheDocument();
  });

  it('renders empty message when items array is empty', () => {
    render(<List items={[]} emptyMessage="No items found" />);

    expect(screen.getByText('No items found')).toBeInTheDocument();
  });

  it('returns null when items array is empty and no empty message', () => {
    const { container } = render(<List items={[]} />);

    expect(container.firstChild).toBeNull();
  });

  it('calls onClick when item is clicked', async () => {
    const user = userEvent.setup();
    const mockOnClick = vi.fn();
    const itemsWithClick: ListItem[] = [
      {
        id: '1',
        content: 'Clickable Item',
        onClick: mockOnClick,
      },
    ];

    render(<List items={itemsWithClick} />);

    const item = screen.getByText('Clickable Item');
    await user.click(item);

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

  it('does not call onClick when item is disabled', async () => {
    const user = userEvent.setup();
    const mockOnClick = vi.fn();
    const itemsWithDisabled: ListItem[] = [
      {
        id: '1',
        content: 'Disabled Item',
        onClick: mockOnClick,
        disabled: true,
      },
    ];

    render(<List items={itemsWithDisabled} />);

    const item = screen.getByText('Disabled Item');
    await user.click(item);

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

  it('renders actions on items', () => {
    render(<List items={mockItems} />);

    const actionButton = screen.getByText('Action');
    expect(actionButton).toBeInTheDocument();
  });

  it('does not trigger item onClick when clicking actions', async () => {
    const user = userEvent.setup();
    const mockOnClick = vi.fn();
    const itemsWithActions: ListItem[] = [
      {
        id: '1',
        content: 'Item with Actions',
        actions: <button>Action</button>,
        onClick: mockOnClick,
      },
    ];

    render(<List items={itemsWithActions} />);

    const actionButton = screen.getByText('Action');
    await user.click(actionButton);

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

  it('applies default variant styles', () => {
    const { container } = render(<List items={mockItems} variant="default" />);

    const list = container.querySelector('ul');
    expect(list).toHaveClass('space-y-1');
  });

  it('applies bordered variant styles', () => {
    const { container } = render(<List items={mockItems} variant="bordered" />);

    const list = container.querySelector('ul');
    expect(list).toHaveClass('border');
    expect(list).toHaveClass('divide-y');
    expect(list).toHaveClass('rounded-md');
  });

  it('applies spaced variant styles', () => {
    const { container } = render(<List items={mockItems} variant="spaced" />);

    const list = container.querySelector('ul');
    expect(list).toHaveClass('space-y-2');
  });

  it('applies custom className', () => {
    const { container } = render(
      <List items={mockItems} className="custom-class" />,
    );

    const list = container.querySelector('ul');
    expect(list).toHaveClass('custom-class');
  });

  it('applies custom itemClassName', () => {
    const { container } = render(
      <List items={mockItems} itemClassName="custom-item-class" />,
    );

    const firstItem = container.querySelector('li');
    expect(firstItem).toHaveClass('custom-item-class');
  });

  it('applies hover styles when item is clickable', () => {
    const clickableItems: ListItem[] = [
      {
        id: '1',
        content: 'Clickable',
        onClick: vi.fn(),
      },
    ];

    const { container } = render(<List items={clickableItems} />);

    const item = container.querySelector('li');
    expect(item).toHaveClass('cursor-pointer');
    expect(item).toHaveClass('hover:bg-accent');
  });

  it('applies disabled styles when item is disabled', () => {
    const disabledItems: ListItem[] = [
      {
        id: '1',
        content: 'Disabled',
        disabled: true,
      },
    ];

    const { container } = render(<List items={disabledItems} />);

    const item = container.querySelector('li');
    expect(item).toHaveClass('cursor-not-allowed');
    expect(item).toHaveClass('opacity-50');
  });

  it('renders items with complex content', () => {
    const complexItems: ListItem[] = [
      {
        id: '1',
        content: (
          <div>
            <h3>Title</h3>
            <p>Description</p>
          </div>
        ),
      },
    ];

    render(<List items={complexItems} />);

    expect(screen.getByText('Title')).toBeInTheDocument();
    expect(screen.getByText('Description')).toBeInTheDocument();
  });

  it('renders items with multiple actions', () => {
    const itemsWithMultipleActions: ListItem[] = [
      {
        id: '1',
        content: 'Item',
        actions: (
          <>
            <button>Edit</button>
            <button>Delete</button>
          </>
        ),
      },
    ];

    render(<List items={itemsWithMultipleActions} />);

    expect(screen.getByText('Edit')).toBeInTheDocument();
    expect(screen.getByText('Delete')).toBeInTheDocument();
  });

  it('handles items without onClick', () => {
    const itemsWithoutClick: ListItem[] = [
      {
        id: '1',
        content: 'Static Item',
      },
    ];

    const { container } = render(<List items={itemsWithoutClick} />);

    const item = container.querySelector('li');
    expect(item).not.toHaveClass('cursor-pointer');
  });

  it('handles items with onClick but no actions', () => {
    const itemsWithClickOnly: ListItem[] = [
      {
        id: '1',
        content: 'Clickable Item',
        onClick: vi.fn(),
      },
    ];

    const { container } = render(<List items={itemsWithClickOnly} />);

    const item = container.querySelector('li');
    expect(item).toHaveClass('cursor-pointer');

    // Actions container should not be rendered
    const actionsContainer = item?.querySelector('.ml-4');
    expect(actionsContainer).not.toBeInTheDocument();
  });
});
