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

import { SortHeader } from './SortHeader';

// SortHeader renders a <th> which needs a parent table structure
function renderSortHeader(props: React.ComponentProps<typeof SortHeader>) {
  return render(
    <table>
      <thead>
        <tr>
          <SortHeader {...props} />
        </tr>
      </thead>
    </table>,
  );
}

describe('SortHeader', () => {
  const defaultProps = {
    column: 'name',
    label: 'Name',
    onSort: vi.fn(),
  };

  it('renders the label text', () => {
    renderSortHeader(defaultProps);
    expect(screen.getByText('Name')).toBeInTheDocument();
  });

  it('has role columnheader', () => {
    renderSortHeader(defaultProps);
    expect(screen.getByRole('columnheader')).toBeInTheDocument();
  });

  it('renders a focusable sort button inside the th', () => {
    renderSortHeader(defaultProps);
    // The inner <button> is the interactive element (no nested-control violation)
    expect(screen.getByRole('button')).toBeInTheDocument();
    // The <th> itself is NOT made focusable (tabIndex would be on the button)
    expect(screen.getByRole('columnheader')).not.toHaveAttribute('tabindex');
  });

  it('calls onSort when the sort button is clicked', async () => {
    const user = userEvent.setup();
    const onSort = vi.fn();
    renderSortHeader({ ...defaultProps, onSort });
    await user.click(screen.getByRole('button'));
    expect(onSort).toHaveBeenCalledWith('name');
  });

  it('calls onSort when Enter is pressed on the sort button', async () => {
    const user = userEvent.setup();
    const onSort = vi.fn();
    renderSortHeader({ ...defaultProps, onSort });
    screen.getByRole('button').focus();
    await user.keyboard('{Enter}');
    expect(onSort).toHaveBeenCalledWith('name');
  });

  it('calls onSort when Space is pressed on the sort button', async () => {
    const user = userEvent.setup();
    const onSort = vi.fn();
    renderSortHeader({ ...defaultProps, onSort });
    screen.getByRole('button').focus();
    await user.keyboard(' ');
    expect(onSort).toHaveBeenCalledWith('name');
  });

  it('shows aria-sort none when not active', () => {
    renderSortHeader({ ...defaultProps, currentSort: 'email', currentDir: 'asc' });
    expect(screen.getByRole('columnheader')).toHaveAttribute('aria-sort', 'none');
  });

  it('shows aria-sort ascending when active and asc', () => {
    renderSortHeader({ ...defaultProps, currentSort: 'name', currentDir: 'asc' });
    expect(screen.getByRole('columnheader')).toHaveAttribute('aria-sort', 'ascending');
  });

  it('shows aria-sort descending when active and desc', () => {
    renderSortHeader({ ...defaultProps, currentSort: 'name', currentDir: 'desc' });
    expect(screen.getByRole('columnheader')).toHaveAttribute('aria-sort', 'descending');
  });

  it('shows up arrow when sorted ascending', () => {
    renderSortHeader({ ...defaultProps, currentSort: 'name', currentDir: 'asc' });
    expect(screen.getByText('↑')).toBeInTheDocument();
  });

  it('shows down arrow when sorted descending', () => {
    renderSortHeader({ ...defaultProps, currentSort: 'name', currentDir: 'desc' });
    expect(screen.getByText('↓')).toBeInTheDocument();
  });

  it('shows no arrow when not active', () => {
    renderSortHeader({ ...defaultProps, currentSort: 'email' });
    expect(screen.queryByText('↑')).not.toBeInTheDocument();
    expect(screen.queryByText('↓')).not.toBeInTheDocument();
  });

  it('UX-209: accepts className and applies it to the th', () => {
    renderSortHeader({ ...defaultProps, className: 'hidden lg:table-cell' });
    expect(screen.getByRole('columnheader')).toHaveClass('hidden');
  });

  it('UX-209: renders ReactNode label (e.g. element with nested tooltip trigger)', () => {
    renderSortHeader({
      ...defaultProps,
      label: <span data-testid="custom-label">Click Δ<span>ℹ</span></span>,
    });
    expect(screen.getByTestId('custom-label')).toBeInTheDocument();
    expect(screen.getByText('Click Δ', { exact: false })).toBeInTheDocument();
  });

  it('renders tooltip outside the sort button to prevent nested interactive controls', () => {
    const onSort = vi.fn();
    renderSortHeader({
      ...defaultProps,
      tooltip: <span data-testid="info-tip">ℹ️</span>,
      onSort,
    });
    const tooltip = screen.getByTestId('info-tip');
    expect(tooltip).toBeInTheDocument();
    // Tooltip must NOT be a descendant of the sort button
    const button = screen.getByRole('button');
    expect(button).not.toContainElement(tooltip);
  });
});
