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

import EntityList from '@/Components/TopicClusters/EntityList';

function makeEntity(overrides: Record<string, unknown> = {}) {
  return {
    id: 1,
    entity_text: 'running shoes',
    entity_type: 'keyword',
    demand_volume: 500,
    coverage_strength: 45.5,
    source: 'query',
    ...overrides,
  };
}

function makeEntities(count: number = 3) {
  return Array.from({ length: count }, (_, i) => ({
    id: i + 1,
    entity_text: `entity ${i + 1}`,
    entity_type: i % 3 === 0 ? 'keyword' : i % 3 === 1 ? 'phrase' : 'question',
    demand_volume: 100 * (i + 1),
    coverage_strength: 20 + i * 15,
    source: i % 2 === 0 ? 'query' : 'page_title',
  }));
}

describe('EntityList', () => {
  it('renders entity text', () => {
    const entities = [makeEntity({ entity_text: 'best running shoes' })];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('best running shoes')).toBeInTheDocument();
  });

  it('renders entity type with capitalization', () => {
    const entities = [makeEntity({ entity_type: 'keyword' })];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('Keyword')).toBeInTheDocument();
  });

  it('formats demand volume with commas', () => {
    const entities = [makeEntity({ demand_volume: 12345 })];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('12,345')).toBeInTheDocument();
  });

  it('formats coverage strength as percentage', () => {
    const entities = [makeEntity({ coverage_strength: 75.789 })];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('75.8%')).toBeInTheDocument();
  });

  it('displays coverage badge with correct variant for high coverage', () => {
    const entities = [makeEntity({ coverage_strength: 85 })];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('85.0%')).toBeInTheDocument();
    // Badge variant is tested via styling and rendering - we just verify it displays
  });

  it('displays coverage badge with medium variant for medium coverage', () => {
    const entities = [makeEntity({ coverage_strength: 50 })];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('50.0%')).toBeInTheDocument();
  });

  it('displays coverage badge with destructive variant for low coverage', () => {
    const entities = [makeEntity({ coverage_strength: 15 })];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('15.0%')).toBeInTheDocument();
  });

  it('applies red styling for low coverage rows', () => {
    const entities = [makeEntity({ coverage_strength: 25 })];
    const { container } = render(<EntityList entities={entities} />);
    const row = container.querySelector('tr.border-l-red-500');
    expect(row).toBeInTheDocument();
  });

  it('applies yellow styling for medium coverage rows', () => {
    const entities = [makeEntity({ coverage_strength: 50 })];
    const { container } = render(<EntityList entities={entities} />);
    const row = container.querySelector('tr.border-l-yellow-500');
    expect(row).toBeInTheDocument();
  });

  it('applies green styling for high coverage rows', () => {
    const entities = [makeEntity({ coverage_strength: 85 })];
    const { container } = render(<EntityList entities={entities} />);
    const row = container.querySelector('tr.border-l-green-500');
    expect(row).toBeInTheDocument();
  });

  it('renders empty state when no entities', () => {
    render(<EntityList entities={[]} />);
    expect(screen.getByText('No entities found in this cluster.')).toBeInTheDocument();
  });

  it('renders multiple entities', () => {
    const entities = makeEntities(5);
    render(<EntityList entities={entities} />);
    expect(screen.getByText('entity 1')).toBeInTheDocument();
    expect(screen.getByText('entity 2')).toBeInTheDocument();
    expect(screen.getByText('entity 5')).toBeInTheDocument();
  });

  it('renders all column headers', () => {
    const entities = [makeEntity()];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('Entity')).toBeInTheDocument();
    expect(screen.getByText('Type')).toBeInTheDocument();
    expect(screen.getByText('Demand')).toBeInTheDocument();
    expect(screen.getByText('Coverage')).toBeInTheDocument();
  });

  it('sorts by demand volume by default in descending order', () => {
    const entities = [
      makeEntity({ id: 1, entity_text: 'a', demand_volume: 100 }),
      makeEntity({ id: 2, entity_text: 'b', demand_volume: 500 }),
      makeEntity({ id: 3, entity_text: 'c', demand_volume: 200 }),
    ];
    const { container } = render(<EntityList entities={entities} />);
    const rows = container.querySelectorAll('tbody tr');
    expect(rows[0]).toHaveTextContent('b'); // 500
    expect(rows[1]).toHaveTextContent('c'); // 200
    expect(rows[2]).toHaveTextContent('a'); // 100
  });

  it('sorts by entity text when clicking entity header', async () => {
    const user = userEvent.setup();
    const entities = [
      makeEntity({ id: 1, entity_text: 'zebra' }),
      makeEntity({ id: 2, entity_text: 'apple' }),
      makeEntity({ id: 3, entity_text: 'banana' }),
    ];
    const { container } = render(<EntityList entities={entities} />);

    const entityButton = screen.getByRole('button', { name: /Entity/i });
    await user.click(entityButton);

    const rows = container.querySelectorAll('tbody tr');
    expect(rows[0]).toHaveTextContent('zebra'); // desc order (z to a)
    expect(rows[1]).toHaveTextContent('banana');
    expect(rows[2]).toHaveTextContent('apple');
  });

  it('toggles sort direction when clicking same header twice', async () => {
    const user = userEvent.setup();
    const entities = [
      makeEntity({ id: 1, entity_text: 'a', demand_volume: 100 }),
      makeEntity({ id: 2, entity_text: 'b', demand_volume: 300 }),
    ];
    const { container } = render(<EntityList entities={entities} />);

    const demandButton = screen.getByRole('button', { name: /Demand/i });

    // First click: already desc by default, so should toggle to asc
    await user.click(demandButton);
    let rows = container.querySelectorAll('tbody tr');
    expect(rows[0]).toHaveTextContent('a'); // 100 (asc)
    expect(rows[1]).toHaveTextContent('b'); // 300

    // Second click: toggle back to desc
    await user.click(demandButton);
    rows = container.querySelectorAll('tbody tr');
    expect(rows[0]).toHaveTextContent('b'); // 300 (desc)
    expect(rows[1]).toHaveTextContent('a'); // 100
  });

  it('sorts by coverage strength when clicking coverage header', async () => {
    const user = userEvent.setup();
    const entities = [
      makeEntity({ id: 1, entity_text: 'a', coverage_strength: 50 }),
      makeEntity({ id: 2, entity_text: 'b', coverage_strength: 80 }),
      makeEntity({ id: 3, entity_text: 'c', coverage_strength: 20 }),
    ];
    const { container } = render(<EntityList entities={entities} />);

    const coverageButton = screen.getByRole('button', { name: /Coverage/i });
    await user.click(coverageButton);

    const rows = container.querySelectorAll('tbody tr');
    expect(rows[0]).toHaveTextContent('b'); // 80% (desc)
    expect(rows[1]).toHaveTextContent('a'); // 50%
    expect(rows[2]).toHaveTextContent('c'); // 20%
  });

  it('displays sort icon for active sort column', () => {
    const entities = [makeEntity()];
    render(<EntityList entities={entities} />);
    // Default sort is demand_volume desc, so should show ArrowDown
    const demandButton = screen.getByRole('button', { name: /Demand/i });
    const icon = demandButton.querySelector('svg.lucide-arrow-down');
    expect(icon).toBeInTheDocument();
  });

  it('handles entity types with various capitalizations', () => {
    const entities = [
      makeEntity({ id: 1, entity_type: 'keyword' }),
      makeEntity({ id: 2, entity_type: 'phrase' }),
      makeEntity({ id: 3, entity_type: 'question' }),
    ];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('Keyword')).toBeInTheDocument();
    expect(screen.getByText('Phrase')).toBeInTheDocument();
    expect(screen.getByText('Question')).toBeInTheDocument();
  });

  it('handles zero demand volume', () => {
    const entities = [makeEntity({ demand_volume: 0 })];
    render(<EntityList entities={entities} />);
    expect(screen.getByText('0')).toBeInTheDocument();
  });

  it('handles coverage at boundary values', () => {
    const entities = [
      makeEntity({ id: 1, coverage_strength: 0 }),
      makeEntity({ id: 2, coverage_strength: 30 }),
      makeEntity({ id: 3, coverage_strength: 70 }),
      makeEntity({ id: 4, coverage_strength: 100 }),
    ];
    const { container } = render(<EntityList entities={entities} />);

    expect(screen.getByText('0.0%')).toBeInTheDocument();
    expect(screen.getByText('30.0%')).toBeInTheDocument();
    expect(screen.getByText('70.0%')).toBeInTheDocument();
    expect(screen.getByText('100.0%')).toBeInTheDocument();

    // Check color coding at boundaries
    const rows = container.querySelectorAll('tbody tr');
    expect(rows[0].className).toContain('border-l-red-500'); // 0%
    expect(rows[1].className).toContain('border-l-yellow-500'); // 30%
    expect(rows[2].className).toContain('border-l-green-500'); // 70%
    expect(rows[3].className).toContain('border-l-green-500'); // 100%
  });

  it('sorts entity text case-insensitively', async () => {
    const user = userEvent.setup();
    const entities = [
      makeEntity({ id: 1, entity_text: 'Zebra' }),
      makeEntity({ id: 2, entity_text: 'apple' }),
      makeEntity({ id: 3, entity_text: 'BANANA' }),
    ];
    const { container } = render(<EntityList entities={entities} />);

    const entityButton = screen.getByRole('button', { name: /Entity/i });
    await user.click(entityButton); // First click: desc
    await user.click(entityButton); // Second click: asc

    const rows = container.querySelectorAll('tbody tr');
    expect(rows[0]).toHaveTextContent('apple');
    expect(rows[1]).toHaveTextContent('BANANA');
    expect(rows[2]).toHaveTextContent('Zebra');
  });
});
