import { test, expect, type ConsoleMessage } from '@playwright/test';
import { ROUTES } from './helpers';

for (const route of ROUTES) {
  test(`${route} renders, has h1, no console errors`, async ({ page }) => {
    // Ignore third-party console noise (AnalyticsHead's hub-gated GA/AdSense
    // inject google.com frames/scripts that 403 or emit report-only CSP
    // notices under real Chrome) — only template errors should fail.
    const THIRD_PARTY = /googlesyndication|google-analytics|googletagmanager|doubleclick|adsbygoogle|gtag|pagead|google\.com|content security policy|frame-ancestors|report-only/i;
    const errors: string[] = [];
    page.on('pageerror', (e) => errors.push(`pageerror: ${e.message}`));
    page.on('console', (m: ConsoleMessage) => {
      if (m.type() !== 'error') return;
      const text = m.text();
      const u = m.location()?.url || '';
      if (THIRD_PARTY.test(text) || THIRD_PARTY.test(u)) return;
      if (/failed to load resource/i.test(text)) return;
      errors.push(`console.error: ${text}`);
    });

    const res = await page.goto(route);
    expect(res, `no response for ${route}`).not.toBeNull();
    expect(res!.status(), `status for ${route}`).toBe(200);
    await expect(page.locator('h1').first()).toBeVisible();
    await expect(page.locator('footer').first()).toBeVisible();
    expect(errors, `console errors on ${route}:\n${errors.join('\n')}`).toEqual([]);
  });
}

test('home meta description is set', async ({ page }) => {
  await page.goto('/');
  const meta = await page.locator('meta[name="description"]').getAttribute('content');
  expect(meta).toBeTruthy();
  expect(meta!.length).toBeGreaterThan(20);
});

test('home emits Periodical JSON-LD with required fields', async ({ page }) => {
  await page.goto('/');
  const scripts = await page.locator('script[type="application/ld+json"]').all();
  const docs = await Promise.all(
    scripts.map(async (s) => {
      try { return JSON.parse((await s.textContent()) || ''); } catch { return null; }
    })
  );
  const periodical = docs.find((d) => d && d['@type'] === 'Periodical');
  expect(periodical, 'Periodical JSON-LD missing').toBeTruthy();
  expect(periodical.name).toBe('Marginalia');
  expect(periodical.url).toMatch(/^https?:\/\//);
  expect(periodical.description).toBeTruthy();
  expect(periodical.inLanguage).toBe('en');
  expect(periodical.publisher).toBeTruthy();
  expect(periodical.publisher['@type']).toBe('Person');
  expect(periodical.publisher.name).toBeTruthy();
});

test('home emits one Article JSON-LD per sample issue (4)', async ({ page }) => {
  await page.goto('/');
  const scripts = await page.locator('script[type="application/ld+json"]').all();
  const docs = await Promise.all(
    scripts.map(async (s) => {
      try { return JSON.parse((await s.textContent()) || ''); } catch { return null; }
    })
  );
  const articles = docs.filter((d) => d && d['@type'] === 'Article');
  expect(articles.length).toBe(4);
  for (const a of articles) {
    expect(a.headline).toBeTruthy();
    expect(a.datePublished).toMatch(/^\d{4}-\d{2}-\d{2}$/);
    expect(a.url).toMatch(/^https?:\/\//);
    expect(a.isPartOf).toBeTruthy();
    expect(a.isPartOf['@type']).toBe('Periodical');
    expect(a.isPartOf.name).toBe('Marginalia');
    expect(a.author).toBeTruthy();
  }
});

test('OG image absolute and 1200×630', async ({ page }) => {
  await page.goto('/');
  const og = await page.locator('meta[property="og:image"]').getAttribute('content');
  expect(og).toMatch(/^https?:\/\//);
  expect(og).toContain('og-image.png');
  expect(await page.locator('meta[property="og:image:width"]').getAttribute('content')).toBe('1200');
  expect(await page.locator('meta[property="og:image:height"]').getAttribute('content')).toBe('630');
});

test('Twitter card is summary_large_image', async ({ page }) => {
  await page.goto('/');
  expect(await page.locator('meta[name="twitter:card"]').getAttribute('content')).toBe('summary_large_image');
});

test('canonical link is absolute', async ({ page }) => {
  await page.goto('/');
  const canonical = await page.locator('link[rel="canonical"]').getAttribute('href');
  expect(canonical).toMatch(/^https?:\/\//);
});

test('sitemap.xml is reachable', async ({ page }) => {
  const res = await page.goto('/sitemap-index.xml');
  expect(res?.status()).toBe(200);
});

test('robots.txt is reachable', async ({ page }) => {
  const res = await page.goto('/robots.txt');
  expect(res?.status()).toBe(200);
});
