import { test, expect, Page } from '@playwright/test';

// Sitemap tests run against the test pod (uses BASE_URL from playwright config)

// Helper to parse sitemap XML
async function parseSitemap(page: Page, url: string): Promise<string[]> {
  const response = await page.goto(url);
  expect(response?.status()).toBe(200);

  const content = await page.content();
  const urls: string[] = [];

  // Extract <loc> elements from sitemap
  const locMatches = content.matchAll(/<loc>([^<]+)<\/loc>/g);
  for (const match of locMatches) {
    urls.push(match[1]);
  }

  return urls;
}

// Helper to get random items from array
function getRandomItems<T>(array: T[], count: number): T[] {
  const shuffled = [...array].sort(() => 0.5 - Math.random());
  return shuffled.slice(0, Math.min(count, array.length));
}

// Helper to convert full URL to relative path
function toRelativePath(url: string): string {
  try {
    const parsed = new URL(url);
    return parsed.pathname;
  } catch {
    // Already relative or invalid
    return url;
  }
}

test.describe('us.elect.info sitemap crawling', () => {
  test.describe.configure({ mode: 'serial' });

  let sitemapIndex: string[] = [];

  test('root sitemap.xml is valid', async ({ page }) => {
    const response = await page.goto(`/sitemap.xml`);
    expect(response?.status()).toBe(200);

    const content = await page.content();
    // Should be a sitemap index
    expect(content).toContain('sitemapindex');
    expect(content).toContain('sitemap');

    // Parse sub-sitemaps
    sitemapIndex = await parseSitemap(page, `/sitemap.xml`);
    expect(sitemapIndex.length).toBeGreaterThan(0);

    console.log(`Found ${sitemapIndex.length} sub-sitemaps`);
  });

  test('candidates section', async ({ page }) => {
    // Visit index page
    const indexResponse = await page.goto(`/candidates/`);
    expect(indexResponse?.status()).toBe(200);
    await expect(page.locator('h1')).toContainText(/Candidates/i);

    // Get links from the page
    const links = await page.locator('.entity-list a').all();
    expect(links.length).toBeGreaterThan(0);

    // Visit 3 random entity pages
    const hrefs = await Promise.all(links.slice(0, 20).map(l => l.getAttribute('href')));
    const randomLinks = getRandomItems(hrefs.filter(Boolean) as string[], 3);

    for (const href of randomLinks) {
      const entityResponse = await page.goto(toRelativePath(href));
      expect(entityResponse?.status()).toBe(200);
      // Entity pages should have a title
      await expect(page.locator('h1')).toBeVisible();
    }
  });

  test('committees section', async ({ page }) => {
    const indexResponse = await page.goto(`/committees/`);
    expect(indexResponse?.status()).toBe(200);
    await expect(page.locator('h1')).toContainText(/Committees/i);

    const links = await page.locator('.entity-list a').all();
    expect(links.length).toBeGreaterThan(0);

    const hrefs = await Promise.all(links.slice(0, 20).map(l => l.getAttribute('href')));
    const randomLinks = getRandomItems(hrefs.filter(Boolean) as string[], 3);

    for (const href of randomLinks) {
      const entityResponse = await page.goto(toRelativePath(href));
      expect(entityResponse?.status()).toBe(200);
      await expect(page.locator('h1')).toBeVisible();
    }
  });

  test('parties section', async ({ page }) => {
    const indexResponse = await page.goto(`/parties/`);
    expect(indexResponse?.status()).toBe(200);
    await expect(page.locator('h1')).toContainText(/Parties/i);

    const links = await page.locator('.entity-list a').all();
    expect(links.length).toBeGreaterThan(0);

    const hrefs = await Promise.all(links.slice(0, 20).map(l => l.getAttribute('href')));
    const randomLinks = getRandomItems(hrefs.filter(Boolean) as string[], 3);

    for (const href of randomLinks) {
      const entityResponse = await page.goto(toRelativePath(href));
      expect(entityResponse?.status()).toBe(200);
      await expect(page.locator('h1')).toBeVisible();
    }
  });

  test('offices section', async ({ page }) => {
    const indexResponse = await page.goto(`/offices/`);
    expect(indexResponse?.status()).toBe(200);
    await expect(page.locator('h1')).toContainText(/Offices/i);

    const links = await page.locator('.entity-list a').all();
    expect(links.length).toBeGreaterThan(0);

    const hrefs = await Promise.all(links.slice(0, 20).map(l => l.getAttribute('href')));
    const randomLinks = getRandomItems(hrefs.filter(Boolean) as string[], 3);

    for (const href of randomLinks) {
      const entityResponse = await page.goto(toRelativePath(href));
      expect(entityResponse?.status()).toBe(200);
      await expect(page.locator('h1')).toBeVisible();
    }
  });

  test('districts section', async ({ page }) => {
    const indexResponse = await page.goto(`/districts/`);
    expect(indexResponse?.status()).toBe(200);
    await expect(page.locator('h1')).toContainText(/Districts/i);

    const links = await page.locator('.entity-list a').all();
    expect(links.length).toBeGreaterThan(0);

    const hrefs = await Promise.all(links.slice(0, 20).map(l => l.getAttribute('href')));
    const randomLinks = getRandomItems(hrefs.filter(Boolean) as string[], 3);

    for (const href of randomLinks) {
      const entityResponse = await page.goto(toRelativePath(href));
      expect(entityResponse?.status()).toBe(200);
      await expect(page.locator('h1')).toBeVisible();
    }
  });

  test('states section', async ({ page }) => {
    const indexResponse = await page.goto(`/states/`);
    expect(indexResponse?.status()).toBe(200);
    await expect(page.locator('h1')).toContainText(/States/i);

    const links = await page.locator('.entity-list a').all();
    expect(links.length).toBeGreaterThan(0);

    const hrefs = await Promise.all(links.slice(0, 20).map(l => l.getAttribute('href')));
    const randomLinks = getRandomItems(hrefs.filter(Boolean) as string[], 3);

    for (const href of randomLinks) {
      const entityResponse = await page.goto(toRelativePath(href));
      expect(entityResponse?.status()).toBe(200);
      await expect(page.locator('h1')).toBeVisible();
    }
  });

  test('elections section', async ({ page }) => {
    const indexResponse = await page.goto(`/elections/`);
    expect(indexResponse?.status()).toBe(200);
    await expect(page.locator('h1')).toContainText(/Election/i);

    const links = await page.locator('.entity-list a').all();
    expect(links.length).toBeGreaterThan(0);

    const hrefs = await Promise.all(links.slice(0, 20).map(l => l.getAttribute('href')));
    const randomLinks = getRandomItems(hrefs.filter(Boolean) as string[], 3);

    for (const href of randomLinks) {
      const entityResponse = await page.goto(toRelativePath(href));
      expect(entityResponse?.status()).toBe(200);
      await expect(page.locator('h1')).toBeVisible();
    }
  });

  test('sub-sitemaps are valid XML', async ({ page }) => {
    // Test each sub-sitemap
    const subSitemaps = [
      '/candidates/sitemap-candidates.xml',
      '/committees/sitemap-committees.xml',
      '/parties/sitemap-parties.xml',
      '/offices/sitemap-offices.xml',
      '/districts/sitemap-districts.xml',
      '/states/sitemap-states.xml',
      '/elections/sitemap-elections.xml',
    ];

    for (const sitemap of subSitemaps) {
      const response = await page.goto(`${sitemap}`);
      expect(response?.status(), `${sitemap} should return 200`).toBe(200);

      const content = await page.content();
      expect(content, `${sitemap} should be valid sitemap`).toContain('urlset');
      expect(content, `${sitemap} should have URLs`).toContain('<loc>');
    }
  });

  test('homepage search works', async ({ page }) => {
    await page.goto(`/`);

    const searchInput = page.locator('#query');
    await expect(searchInput).toBeVisible();

    // Test search for a common name
    await searchInput.fill('Biden');
    await searchInput.press('Enter');

    // Results should appear
    await expect(page.locator('#results')).toHaveClass(/active/, { timeout: 10000 });

    // Should have at least one result
    const results = await page.locator('#results .result-item, #results li').count();
    expect(results).toBeGreaterThan(0);
  });
});
