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

// ── Header layout ─────────────────────────────────────────────────────────

test('header shows the full name', async ({ page }) => {
  await page.goto('/');
  await expect(page.locator('header.cv-header-nav').getByText('Nadia Costa')).toBeVisible();
});

test('header has paper-size toggle (A4 / Letter), theme toggle, Download PDF', async ({ page }) => {
  await page.goto('/');
  // Paper toggle
  await expect(page.getByRole('button', { name: 'A4', exact: true })).toBeVisible();
  await expect(page.getByRole('button', { name: 'Letter', exact: true })).toBeVisible();
  // Theme toggle
  await expect(page.getByRole('button', { name: /toggle theme/i })).toBeVisible();
  // Download PDF
  await expect(page.getByRole('button', { name: /download pdf/i })).toBeVisible();
});

// ── Resume content ────────────────────────────────────────────────────────

test('main column has Summary, Experience, Selected Projects, Education sections', async ({ page }) => {
  await page.goto('/');
  for (const heading of ['Summary', 'Experience', 'Selected Projects', 'Education']) {
    await expect(page.getByRole('heading', { name: heading, exact: true })).toBeVisible();
  }
});

test('aside has Skills and Languages sections', async ({ page }) => {
  await page.goto('/');
  for (const heading of ['Skills', 'Languages']) {
    await expect(page.getByRole('heading', { name: heading, exact: true })).toBeVisible();
  }
});

test('experience lists 4 jobs', async ({ page }) => {
  await page.goto('/');
  // <ol role="list"> inside the experience section
  const jobs = page.locator('section[aria-labelledby="experience-heading"] > ol > li');
  expect(await jobs.count()).toBe(4);
});

test('selected projects lists 4 projects', async ({ page }) => {
  await page.goto('/');
  const projects = page.locator('section[aria-labelledby="projects-heading"] > ul > li');
  expect(await projects.count()).toBe(4);
});

test('education lists 2 entries', async ({ page }) => {
  await page.goto('/');
  const edu = page.locator('section[aria-labelledby="education-heading"] > ol > li');
  expect(await edu.count()).toBe(2);
});

test('skills lists 3 categories with tags', async ({ page }) => {
  await page.goto('/');
  const skillGroups = page.locator('section[aria-labelledby="skills-heading"] dl > div');
  expect(await skillGroups.count()).toBe(3);
});

test('languages lists 3 entries', async ({ page }) => {
  await page.goto('/');
  const langs = page.locator('section[aria-labelledby="languages-heading"] > ul > li');
  expect(await langs.count()).toBe(3);
});

// ── Header contact links ─────────────────────────────────────────────────

test('header contact strip has email, LinkedIn, GitHub', async ({ page }) => {
  await page.goto('/');
  const screenHeader = page.locator('main > article > header');
  await expect(screenHeader.locator('[data-contact-link="email"]')).toBeVisible();
  await expect(screenHeader.locator('[data-contact-link="linkedin"]')).toBeVisible();
  await expect(screenHeader.locator('[data-contact-link="github"]')).toBeVisible();
});

test('LinkedIn appears before email in the on-screen header', async ({ page }) => {
  await page.goto('/');
  // The screen header has email + LinkedIn + GitHub; the convention is
  // LinkedIn primary among CTA-style links. Email is text-first so it appears
  // first in DOM order — but LinkedIn has the accent color (the visual primary).
  // Verify LinkedIn link uses the accent-deep color.
  const linkedin = page.locator('main [data-contact-link="linkedin"]').first();
  const color = await linkedin.evaluate((el) => getComputedStyle(el).color);
  // accent-deep #1E293B → rgb(30, 41, 59)
  expect(color).toBe('rgb(30, 41, 59)');
});

// ── Theme toggle ──────────────────────────────────────────────────────────

test('theme toggle flips the dark class and persists', async ({ page }) => {
  await page.goto('/');
  // Reset
  await page.evaluate(() => {
    localStorage.removeItem('theme');
    document.documentElement.classList.remove('dark');
  });
  await page.reload();

  const before = await page.evaluate(() => document.documentElement.classList.contains('dark'));
  await page.getByRole('button', { name: /toggle theme/i }).click();
  const after = await page.evaluate(() => document.documentElement.classList.contains('dark'));
  expect(after).toBe(!before);

  const stored = await page.evaluate(() => localStorage.getItem('theme'));
  expect(stored).toMatch(/^(light|dark)$/);
});

// ── Paper-size toggle ─────────────────────────────────────────────────────

test('paper-size toggle defaults to A4 and switches to Letter', async ({ page }) => {
  await page.goto('/');
  // Default
  expect(await page.evaluate(() => document.body.dataset.paper)).toBe('a4');
  expect(await page.getByRole('button', { name: 'A4', exact: true }).getAttribute('aria-pressed')).toBe('true');
  expect(await page.getByRole('button', { name: 'Letter', exact: true }).getAttribute('aria-pressed')).toBe('false');

  // Click Letter
  await page.getByRole('button', { name: 'Letter', exact: true }).click();
  expect(await page.evaluate(() => document.body.dataset.paper)).toBe('letter');
  expect(await page.getByRole('button', { name: 'Letter', exact: true }).getAttribute('aria-pressed')).toBe('true');
  expect(await page.getByRole('button', { name: 'A4', exact: true }).getAttribute('aria-pressed')).toBe('false');

  // Persists
  expect(await page.evaluate(() => localStorage.getItem('paper'))).toBe('letter');
});

// ── Download PDF — calls window.print() ──────────────────────────────────

test('Download PDF button triggers window.print()', async ({ page }) => {
  await page.goto('/');
  // Spy on window.print before clicking.
  await page.evaluate(() => {
    (window as any).__printCount = 0;
    const original = window.print;
    window.print = () => { (window as any).__printCount++; };
    (window as any).__originalPrint = original;
  });
  await page.getByRole('button', { name: /download pdf/i }).click();
  const calls = await page.evaluate(() => (window as any).__printCount);
  expect(calls).toBe(1);
});

// ── Print stylesheet — chrome hidden in print emulation ───────────────────

test('print emulation hides the sticky header, paper toggle, theme toggle, and donate link', async ({ page }) => {
  await page.goto('/');
  await page.emulateMedia({ media: 'print' });

  // Sticky on-screen header is hidden
  const navHeader = page.locator('header.cv-header-nav');
  expect(await navHeader.evaluate((el) => getComputedStyle(el).display)).toBe('none');

  // Paper toggle hidden
  const paperToggle = page.locator('.paper-toggle');
  expect(await paperToggle.evaluate((el) => getComputedStyle(el).display)).toBe('none');

  // Footer hidden
  const footer = page.locator('article > footer');
  expect(await footer.evaluate((el) => getComputedStyle(el).display)).toBe('none');
});

test('print emulation keeps the on-screen header visible (h1, contact strip)', async ({ page }) => {
  await page.goto('/');
  await page.emulateMedia({ media: 'print' });
  // The article header itself stays visible (no data-print-hide on it).
  // Only the eyebrow + decorative meta lines are hidden via data-print-hide.
  const articleHeader = page.locator('article > header');
  expect(await articleHeader.evaluate((el) => getComputedStyle(el).display)).not.toBe('none');
  // The h1 is visible
  const h1 = page.locator('article > header h1');
  expect(await h1.evaluate((el) => getComputedStyle(el).display)).not.toBe('none');
});

test('print forces light colors regardless of dark-mode setting', async ({ page }) => {
  await page.goto('/');
  // Force dark mode
  await page.evaluate(() => {
    document.documentElement.classList.add('dark');
    document.documentElement.dataset.theme = 'dark';
  });
  // Now switch to print emulation
  await page.emulateMedia({ media: 'print' });

  const bg = await page.evaluate(() => getComputedStyle(document.body).backgroundColor);
  const fg = await page.evaluate(() => getComputedStyle(document.body).color);
  // body bg should be white in print
  expect(bg).toBe('rgb(255, 255, 255)');
  // body fg should be black-ish
  expect(fg).toBe('rgb(0, 0, 0)');
});

// ── No skill bars / progress meters (anti-pattern check) ─────────────────

test('no skill-bar / progress meters in the markup', async ({ page }) => {
  await page.goto('/');
  // The anti-pattern: <progress>, .skill-bar, role="progressbar" inside skills.
  const skillsSection = page.locator('section[aria-labelledby="skills-heading"]');
  expect(await skillsSection.locator('progress').count()).toBe(0);
  expect(await skillsSection.locator('[role="progressbar"]').count()).toBe(0);
  expect(await skillsSection.locator('.skill-bar, .progress, [class*="bar"]').count()).toBe(0);
});

// ── No photo of subject (bias / layout) ──────────────────────────────────

test('no photo of the subject in the resume', async ({ page }) => {
  await page.goto('/');
  // Allow only the OG image meta tag to reference photos; no <img> in the body.
  const bodyImages = page.locator('body img:not([alt=""])');
  expect(await bodyImages.count()).toBe(0);
});
