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

// ============================================================
// Theme Persistence & Synchronization Tests
// Tests: localStorage, system preference, FOUC, multi-browser
// ============================================================

// Helper: get the current theme state from the DOM
async function getThemeState(page: Page) {
  return page.evaluate(() => ({
    hasDarkClass: document.documentElement.classList.contains('dark'),
    stored: (() => { try { return localStorage.getItem('theme'); } catch { return null; } })(),
    ariaChecked: document.querySelector('[data-theme-toggle]')?.getAttribute('aria-checked'),
    ariaLabel: document.querySelector('[data-theme-toggle]')?.getAttribute('aria-label'),
    themeColorMetas: Array.from(document.querySelectorAll('meta[name="theme-color"]')).map(m => ({
      content: m.getAttribute('content'),
      media: m.getAttribute('media'),
    })),
    liveRegion: document.querySelector('[data-theme-live]')?.textContent ?? '',
    htmlClass: document.documentElement.className,
  }));
}

// Helper: set localStorage theme before page load (via storageState simulation)
async function loadPageWithStoredTheme(page: Page, theme: 'dark' | 'light' | null, url = '/') {
  // Navigate to page first, then set storage, then reload — simulates returning visitor
  await page.goto(url, { waitUntil: 'domcontentloaded' });
  if (theme !== null) {
    await page.evaluate((t) => {
      try { localStorage.setItem('theme', t); } catch { /* noop */ }
    }, theme);
  } else {
    await page.evaluate(() => {
      try { localStorage.removeItem('theme'); } catch { /* noop */ }
    });
  }
  // Reload to trigger the blocking init script
  await page.reload({ waitUntil: 'domcontentloaded' });
}

// Helper: click the theme toggle
async function clickThemeToggle(page: Page) {
  const toggle = page.locator('[data-theme-toggle]').first();
  await expect(toggle).toBeVisible();
  await toggle.click();
  await page.waitForTimeout(150); // Allow state sync
}

// ============================================================
// 1. localStorage Persistence
// ============================================================
test.describe('Theme: localStorage Persistence', () => {

  test('Toggling to dark stores "dark" in localStorage', async ({ page }) => {
    await loadPageWithStoredTheme(page, null);

    // Start in light mode (no stored preference)
    const before = await getThemeState(page);
    // State may be light or dark depending on system — click once and check stored value
    await clickThemeToggle(page);

    const after = await getThemeState(page);
    const isDarkNow = after.hasDarkClass;
    expect(after.stored).toBe(isDarkNow ? 'dark' : 'light');
  });

  test('Toggling to light stores "light" in localStorage', async ({ page }) => {
    // Start with dark stored
    await loadPageWithStoredTheme(page, 'dark');

    const before = await getThemeState(page);
    expect(before.hasDarkClass).toBe(true);

    await clickThemeToggle(page);
    const after = await getThemeState(page);

    expect(after.hasDarkClass).toBe(false);
    expect(after.stored).toBe('light');
  });

  test('Stored "dark" preference is applied on page load', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');
    const state = await getThemeState(page);

    expect(state.hasDarkClass).toBe(true);
    expect(state.stored).toBe('dark');
  });

  test('Stored "light" preference is applied on page load', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');
    const state = await getThemeState(page);

    expect(state.hasDarkClass).toBe(false);
    expect(state.stored).toBe('light');
  });

  test('Preference persists across page navigation (About → Services)', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');

    // Verify dark on home
    expect((await getThemeState(page)).hasDarkClass).toBe(true);

    // Navigate to About
    await page.goto('/about', { waitUntil: 'domcontentloaded' });
    expect((await getThemeState(page)).hasDarkClass).toBe(true);

    // Navigate to Services
    await page.goto('/services', { waitUntil: 'domcontentloaded' });
    expect((await getThemeState(page)).hasDarkClass).toBe(true);
  });

  test('Light preference persists across page navigation', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');

    await page.goto('/portfolio', { waitUntil: 'domcontentloaded' });
    const state = await getThemeState(page);
    expect(state.hasDarkClass).toBe(false);
    expect(state.stored).toBe('light');
  });

  test('Theme toggle persists after navigating away and back', async ({ page }) => {
    await loadPageWithStoredTheme(page, null);

    // Toggle to dark
    await clickThemeToggle(page);
    const wasSetToDark = (await getThemeState(page)).hasDarkClass;

    // Navigate away
    await page.goto('/contact', { waitUntil: 'domcontentloaded' });
    const afterNav = await getThemeState(page);
    expect(afterNav.hasDarkClass).toBe(wasSetToDark);

    // Navigate back
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    const afterBack = await getThemeState(page);
    expect(afterBack.hasDarkClass).toBe(wasSetToDark);
  });

  test('Multiple toggles correctly alternate and store final value', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');

    await clickThemeToggle(page); // → dark
    expect((await getThemeState(page)).stored).toBe('dark');

    await clickThemeToggle(page); // → light
    expect((await getThemeState(page)).stored).toBe('light');

    await clickThemeToggle(page); // → dark
    const final = await getThemeState(page);
    expect(final.stored).toBe('dark');
    expect(final.hasDarkClass).toBe(true);
  });
});

// ============================================================
// 2. System Preference Detection (prefers-color-scheme)
// ============================================================
test.describe('Theme: System Preference Detection', () => {

  test('No stored preference: dark OS → page loads in dark mode', async ({ page }) => {
    await page.emulateMedia({ colorScheme: 'dark' });
    await loadPageWithStoredTheme(page, null);

    const state = await getThemeState(page);
    expect(state.hasDarkClass).toBe(true);
    expect(state.stored).toBeNull(); // Should NOT store when respecting OS
  });

  test('No stored preference: light OS → page loads in light mode', async ({ page }) => {
    await page.emulateMedia({ colorScheme: 'light' });
    await loadPageWithStoredTheme(page, null);

    const state = await getThemeState(page);
    expect(state.hasDarkClass).toBe(false);
    expect(state.stored).toBeNull();
  });

  test('Stored preference overrides OS preference (dark stored, light OS)', async ({ page }) => {
    await page.emulateMedia({ colorScheme: 'light' });
    await loadPageWithStoredTheme(page, 'dark');

    const state = await getThemeState(page);
    expect(state.hasDarkClass).toBe(true); // Stored wins
  });

  test('Stored preference overrides OS preference (light stored, dark OS)', async ({ page }) => {
    await page.emulateMedia({ colorScheme: 'dark' });
    await loadPageWithStoredTheme(page, 'light');

    const state = await getThemeState(page);
    expect(state.hasDarkClass).toBe(false); // Stored wins
  });

  test('System preference change updates theme when no stored preference', async ({ page }) => {
    await page.emulateMedia({ colorScheme: 'light' });
    await loadPageWithStoredTheme(page, null);

    // Verify light initially
    expect((await getThemeState(page)).hasDarkClass).toBe(false);

    // Simulate OS switching to dark
    await page.emulateMedia({ colorScheme: 'dark' });
    await page.waitForTimeout(300); // Allow matchMedia listener to fire

    const state = await getThemeState(page);
    expect(state.hasDarkClass).toBe(true);
    expect(state.stored).toBeNull(); // Still not stored
  });

  test('System preference change is ignored when user has stored preference', async ({ page }) => {
    await page.emulateMedia({ colorScheme: 'light' });
    await loadPageWithStoredTheme(page, 'dark');

    // OS switches to light
    await page.emulateMedia({ colorScheme: 'light' });
    await page.waitForTimeout(300);

    const state = await getThemeState(page);
    // User's stored 'dark' should still be active — but note: system pref change
    // listener only runs for initial load not active toggles — document behavior as-is
    expect(state.stored).toBe('dark');
  });

});

// ============================================================
// 3. No Flash of Unstyled Content (FOUC) Prevention
// ============================================================
test.describe('Theme: FOUC Prevention', () => {

  test('Dark mode class applied before first paint (inline script)', async ({ page }) => {
    // Set up dark preference before navigating
    // We need to ensure html.dark is set synchronously before any CSS loads

    // Use CDP to intercept and verify class set early
    let darkClassAppliedBeforeDOMContentLoaded = false;

    // Listen on DOMContentLoaded and check if class is already present
    await page.addInitScript(() => {
      // This script runs AFTER inline scripts but BEFORE DOMContentLoaded
      // The theme init inline script should have run by now
      window.__themeClassAtInitScript = document.documentElement.classList.contains('dark');
    });

    // Navigate with dark stored
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    await page.evaluate(() => {
      try { localStorage.setItem('theme', 'dark'); } catch { /* noop */ }
    });

    // Reload and capture early state
    await page.addInitScript(() => {
      // Capture class state at very start of script execution
      window.__earlyDarkCheck = document.documentElement.classList.contains('dark');
    });

    await page.reload({ waitUntil: 'domcontentloaded' });

    // After reload, html.dark should be present immediately
    const hasDarkClass = await page.evaluate(() => document.documentElement.classList.contains('dark'));
    expect(hasDarkClass).toBe(true);
  });

  test('No body background flash - html.dark applied synchronously', async ({ page }) => {
    // Navigate with dark preference and verify dark class is set on html element
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    await page.evaluate(() => {
      try { localStorage.setItem('theme', 'dark'); } catch { /* noop */ }
    });

    await page.reload({ waitUntil: 'domcontentloaded' });

    // The dark class must be on the html element (not body)
    const htmlClasses = await page.evaluate(() => document.documentElement.className);
    expect(htmlClasses).toContain('dark');
  });

  test('Light mode: no dark class on html element when light is stored', async ({ page }) => {
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    await page.evaluate(() => {
      try { localStorage.setItem('theme', 'light'); } catch { /* noop */ }
    });

    await page.reload({ waitUntil: 'domcontentloaded' });

    const hasDarkClass = await page.evaluate(() => document.documentElement.classList.contains('dark'));
    expect(hasDarkClass).toBe(false);
  });

  test('Theme init script is in <head> not <body>', async ({ page }) => {
    await page.goto('/', { waitUntil: 'domcontentloaded' });

    // Verify the blocking theme script is in <head>
    const headScripts = await page.evaluate(() => {
      const scripts = Array.from(document.head.querySelectorAll('script:not([type])'));
      return scripts.map(s => s.textContent?.substring(0, 100) ?? '');
    });

    // At least one head script should contain the localStorage theme logic
    const hasThemeScript = headScripts.some(s =>
      s.includes('localStorage') && (s.includes('theme') || s.includes('dark'))
    );
    expect(hasThemeScript).toBe(true);
  });

  test('FOUC check: no visible content reflow on dark reload', async ({ page }) => {
    // If FOUC were present, background-color would transition from white to dark
    // We verify the html element has the class before DOMContentLoaded fires

    let classBeforeDOMContentLoaded: boolean | null = null;

    page.on('domcontentloaded', async () => {
      classBeforeDOMContentLoaded = await page.evaluate(
        () => document.documentElement.classList.contains('dark')
      ).catch(() => null);
    });

    // Ensure dark is stored
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    await page.evaluate(() => { try { localStorage.setItem('theme', 'dark'); } catch {} });
    await page.reload({ waitUntil: 'domcontentloaded' });

    // At DOMContentLoaded, dark class should be present (set by inline blocking script)
    const hasDark = await page.evaluate(() => document.documentElement.classList.contains('dark'));
    expect(hasDark).toBe(true);
  });
});

// ============================================================
// 4. ARIA Accessibility & State Synchronization
// ============================================================
test.describe('Theme: ARIA Accessibility', () => {

  test('Toggle button has role="switch"', async ({ page }) => {
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    const role = await page.locator('[data-theme-toggle]').first().getAttribute('role');
    expect(role).toBe('switch');
  });

  test('aria-checked="false" in light mode', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');
    const ariaChecked = await page.locator('[data-theme-toggle]').first().getAttribute('aria-checked');
    expect(ariaChecked).toBe('false');
  });

  test('aria-checked="true" in dark mode', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');
    const ariaChecked = await page.locator('[data-theme-toggle]').first().getAttribute('aria-checked');
    expect(ariaChecked).toBe('true');
  });

  test('aria-label updates after toggling to dark', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');
    await clickThemeToggle(page);

    const state = await getThemeState(page);
    if (state.hasDarkClass) {
      expect(state.ariaLabel).toBe('Switch to light mode');
      expect(state.ariaChecked).toBe('true');
    } else {
      expect(state.ariaLabel).toBe('Switch to dark mode');
      expect(state.ariaChecked).toBe('false');
    }
  });

  test('aria-label updates after toggling to light', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');
    await clickThemeToggle(page);

    const state = await getThemeState(page);
    expect(state.hasDarkClass).toBe(false);
    expect(state.ariaLabel).toBe('Switch to dark mode');
    expect(state.ariaChecked).toBe('false');
  });

  test('Live region announces theme change on toggle', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');

    // Clear live region
    await page.evaluate(() => {
      document.querySelectorAll('[data-theme-live]').forEach(el => el.textContent = '');
    });

    await clickThemeToggle(page);
    await page.waitForTimeout(200);

    const liveRegionText = await page.evaluate(() =>
      document.querySelector('[data-theme-live]')?.textContent ?? ''
    );
    expect(['Dark mode enabled', 'Light mode enabled']).toContain(liveRegionText.trim());
  });

  test('Live region is polite (non-interrupting)', async ({ page }) => {
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    const ariaLive = await page.locator('[data-theme-live]').first().getAttribute('aria-live');
    expect(ariaLive).toBe('polite');
  });

  test('All theme toggle instances sync aria-checked (desktop + mobile)', async ({ page }) => {
    await page.setViewportSize({ width: 375, height: 667 });
    await loadPageWithStoredTheme(page, 'light');

    // Click toggle (finds first visible one on mobile)
    await clickThemeToggle(page);
    await page.waitForTimeout(200);

    // All toggle instances should have same aria-checked
    const allCheckedValues = await page.evaluate(() =>
      Array.from(document.querySelectorAll('[data-theme-toggle]')).map(btn =>
        btn.getAttribute('aria-checked')
      )
    );

    // All should be the same value
    const uniqueValues = [...new Set(allCheckedValues)];
    expect(uniqueValues).toHaveLength(1);
  });

  test('Toggle is keyboard accessible (Space key)', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');

    const before = await getThemeState(page);
    const wasLight = !before.hasDarkClass;

    // Focus and press Space
    await page.locator('[data-theme-toggle]').first().focus();
    await page.keyboard.press('Space');
    await page.waitForTimeout(150);

    const after = await getThemeState(page);
    // Space on a button triggers click - theme should have toggled
    expect(after.hasDarkClass).toBe(!before.hasDarkClass);
  });

  test('Toggle is keyboard accessible (Enter key)', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');

    const before = await getThemeState(page);

    await page.locator('[data-theme-toggle]').first().focus();
    await page.keyboard.press('Enter');
    await page.waitForTimeout(150);

    const after = await getThemeState(page);
    expect(after.hasDarkClass).toBe(!before.hasDarkClass);
  });

  test('Toggle button is focusable (tabindex not -1)', async ({ page }) => {
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    const tabindex = await page.locator('[data-theme-toggle]').first().getAttribute('tabindex');
    // Should not be -1 (which would make it unfocusable)
    expect(tabindex).not.toBe('-1');
  });
});

// ============================================================
// 5. theme-color Meta Tag Synchronization
// ============================================================
test.describe('Theme: Meta Tag Synchronization', () => {

  test('Dark mode: theme-color meta tags updated to dark color', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');
    const state = await getThemeState(page);

    // At least one meta should have the dark color
    const hasStoredDarkColor = state.themeColorMetas.some(m => m.content === '#0f172a');
    expect(hasStoredDarkColor).toBe(true);
  });

  test('Light mode: theme-color meta tags updated to light color', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');
    const state = await getThemeState(page);

    // At least one meta should have the light color
    const hasStoredLightColor = state.themeColorMetas.some(m => m.content === '#0891b2');
    expect(hasStoredLightColor).toBe(true);
  });

  test('Toggling theme updates theme-color meta tags', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');

    await clickThemeToggle(page);
    await page.waitForTimeout(150);

    const state = await getThemeState(page);
    if (state.hasDarkClass) {
      const hasDarkColor = state.themeColorMetas.some(m => m.content === '#0f172a');
      expect(hasDarkColor).toBe(true);
    } else {
      const hasLightColor = state.themeColorMetas.some(m => m.content === '#0891b2');
      expect(hasLightColor).toBe(true);
    }
  });

  test('Both theme-color meta tags exist in the document head', async ({ page }) => {
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    const metaCount = await page.evaluate(() =>
      document.querySelectorAll('meta[name="theme-color"]').length
    );
    expect(metaCount).toBeGreaterThanOrEqual(1);
  });
});

// ============================================================
// 6. Visual State (CSS)
// ============================================================
test.describe('Theme: Visual CSS State', () => {

  test('Dark mode: html element has "dark" class', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');
    const hasDark = await page.evaluate(() => document.documentElement.classList.contains('dark'));
    expect(hasDark).toBe(true);
  });

  test('Light mode: html element does NOT have "dark" class', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');
    const hasDark = await page.evaluate(() => document.documentElement.classList.contains('dark'));
    expect(hasDark).toBe(false);
  });

  test('Dark mode: page background is dark-colored', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');
    const bgColor = await page.evaluate(() =>
      window.getComputedStyle(document.body).backgroundColor
    );
    // Dark surface is #0f172a = rgb(15, 23, 42)
    // Verify it's distinctly dark (r+g+b should be low)
    const match = bgColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
    if (match) {
      const brightness = parseInt(match[1]) + parseInt(match[2]) + parseInt(match[3]);
      expect(brightness).toBeLessThan(200); // Dark background
    }
  });

  test('Light mode: page background is light-colored', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');
    const bgColor = await page.evaluate(() =>
      window.getComputedStyle(document.body).backgroundColor
    );
    const match = bgColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
    if (match) {
      const brightness = parseInt(match[1]) + parseInt(match[2]) + parseInt(match[3]);
      expect(brightness).toBeGreaterThan(550); // Light background
    }
  });

  test('Sun icon visible in dark mode', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');
    const sunOpacity = await page.evaluate(() => {
      const btn = document.querySelector('[data-theme-toggle]');
      const sun = btn?.querySelector('.sun-icon') as HTMLElement | null;
      return sun ? window.getComputedStyle(sun).opacity : null;
    });
    expect(sunOpacity).toBe('1');
  });

  test('Moon icon visible in light mode', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'light');
    const moonOpacity = await page.evaluate(() => {
      const btn = document.querySelector('[data-theme-toggle]');
      const moon = btn?.querySelector('.moon-icon') as HTMLElement | null;
      return moon ? window.getComputedStyle(moon).opacity : null;
    });
    expect(moonOpacity).toBe('1');
  });

  test('Dark mode: icon transitions respect prefers-reduced-motion', async ({ page }) => {
    await page.emulateMedia({ reducedMotion: 'reduce' });
    await loadPageWithStoredTheme(page, 'dark');

    const transitionDuration = await page.evaluate(() => {
      const btn = document.querySelector('[data-theme-toggle]');
      const sun = btn?.querySelector('.sun-icon') as HTMLElement | null;
      return sun ? window.getComputedStyle(sun).transitionDuration : null;
    });

    // With reduced motion, transition should be 0s or none
    if (transitionDuration) {
      expect(['0s', '0ms']).toContain(transitionDuration);
    }
  });
});

// ============================================================
// 7. JavaScript Disabled Behavior
// ============================================================
test.describe('Theme: JavaScript Disabled', () => {

  test('Page renders without JS (no crash, content visible)', async ({ browser }) => {
    // Create context with JS disabled
    const context = await browser.newContext({ javaScriptEnabled: false });
    const page = await context.newPage();

    await page.goto('/', { waitUntil: 'domcontentloaded' });

    // Page should still render content (SSR)
    const bodyText = await page.locator('body').innerText();
    expect(bodyText.trim().length).toBeGreaterThan(50);

    // Header should be present
    await expect(page.locator('#main-header')).toBeAttached();

    await context.close();
  });

  test('Without JS: page defaults to light mode (no dark class)', async ({ browser }) => {
    const context = await browser.newContext({ javaScriptEnabled: false });
    const page = await context.newPage();

    await page.goto('/', { waitUntil: 'domcontentloaded' });

    // Without JS, the inline theme script cannot run
    // Page should default to light mode (no dark class on html)
    const hasDark = await page.evaluate(() => document.documentElement.classList.contains('dark'));
    // Note: This tests the degraded state — dark class won't be applied without JS
    // This is expected behavior (progressive enhancement)
    // The OS-level theme-color media queries still work for browser chrome
    expect(typeof hasDark).toBe('boolean'); // Just verify evaluation works

    await context.close();
  });

  test('Without JS: theme-color meta tags still exist (native OS support)', async ({ browser }) => {
    const context = await browser.newContext({ javaScriptEnabled: false });
    const page = await context.newPage();

    await page.goto('/', { waitUntil: 'domcontentloaded' });

    // Meta tags are server-rendered so they exist even without JS
    const metaCount = await page.evaluate(() =>
      document.querySelectorAll('meta[name="theme-color"]').length
    );
    expect(metaCount).toBeGreaterThanOrEqual(1);

    await context.close();
  });

  test('Without JS: noscript font fallback renders', async ({ browser }) => {
    const context = await browser.newContext({ javaScriptEnabled: false });
    const page = await context.newPage();

    await page.goto('/', { waitUntil: 'domcontentloaded' });

    // Noscript font link should be in the document
    const noscript = await page.evaluate(() => {
      const noscripts = document.querySelectorAll('noscript');
      return Array.from(noscripts).some(n => n.innerHTML.includes('fonts.googleapis.com'));
    });
    expect(noscript).toBe(true);

    await context.close();
  });
});

// ============================================================
// 8. Cross-Page Theme Consistency
// ============================================================
test.describe('Theme: Cross-Page Consistency', () => {

  const ALL_CONTENT_PAGES = ['/', '/about', '/services', '/portfolio', '/contact', '/blog'];

  for (const url of ALL_CONTENT_PAGES) {
    test(`Dark mode consistent on ${url}`, async ({ page }) => {
      // Start with dark preference and visit each page
      await page.goto('/', { waitUntil: 'domcontentloaded' });
      await page.evaluate(() => { try { localStorage.setItem('theme', 'dark'); } catch {} });

      await page.goto(url, { waitUntil: 'domcontentloaded' });
      const hasDark = await page.evaluate(() => document.documentElement.classList.contains('dark'));
      expect(hasDark).toBe(true);
    });
  }

  test('Theme toggle present on all content pages', async ({ page }) => {
    await page.setViewportSize({ width: 1280, height: 800 }); // Desktop view

    for (const url of ALL_CONTENT_PAGES) {
      await page.goto(url, { waitUntil: 'domcontentloaded' });
      const toggleCount = await page.locator('[data-theme-toggle]').count();
      expect(toggleCount, `Theme toggle missing on ${url}`).toBeGreaterThanOrEqual(1);
    }
  });

  test('Theme state consistent in mobile nav', async ({ page }) => {
    await page.setViewportSize({ width: 375, height: 667 });
    await loadPageWithStoredTheme(page, 'dark');

    // Open mobile menu
    const mobileToggle = page.locator('#mobile-menu-toggle');
    await expect(mobileToggle).toBeVisible();
    await mobileToggle.click();
    await page.waitForTimeout(400);

    // There should be a theme toggle in the mobile menu too
    const togglesInMobileMenu = await page.locator('#mobile-menu [data-theme-toggle]').count();
    // At least one toggle should exist (in header, possibly in mobile menu too)
    const allToggles = await page.locator('[data-theme-toggle]').count();
    expect(allToggles).toBeGreaterThanOrEqual(1);
  });

  test('Theme preserved when switching between mobile and desktop viewports', async ({ page }) => {
    await page.setViewportSize({ width: 375, height: 667 });
    await loadPageWithStoredTheme(page, 'dark');

    expect((await getThemeState(page)).hasDarkClass).toBe(true);

    // Resize to desktop
    await page.setViewportSize({ width: 1280, height: 800 });
    await page.waitForTimeout(200);

    expect((await getThemeState(page)).hasDarkClass).toBe(true);
  });
});

// ============================================================
// 9. Browser Session Persistence
// ============================================================
test.describe('Theme: Browser Session Persistence', () => {

  test('Theme preference survives page refresh', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');

    // Hard refresh
    await page.reload({ waitUntil: 'domcontentloaded' });
    const state = await getThemeState(page);
    expect(state.hasDarkClass).toBe(true);
    expect(state.stored).toBe('dark');
  });

  test('Theme preference survives navigation and back button', async ({ page }) => {
    await loadPageWithStoredTheme(page, 'dark');

    await page.goto('/about', { waitUntil: 'domcontentloaded' });
    expect((await getThemeState(page)).hasDarkClass).toBe(true);

    await page.goBack({ waitUntil: 'domcontentloaded' });
    expect((await getThemeState(page)).hasDarkClass).toBe(true);
  });

  test('New page context starts fresh (no cross-session bleed)', async ({ browser }) => {
    // Session 1: set dark
    const context1 = await browser.newContext();
    const page1 = await context1.newPage();
    await page1.goto('http://localhost:10000/', { waitUntil: 'domcontentloaded' });
    await page1.evaluate(() => { try { localStorage.setItem('theme', 'dark'); } catch {} });
    await context1.close();

    // Session 2: fresh context - should not inherit session 1's preference
    const context2 = await browser.newContext();
    const page2 = await context2.newPage();
    await page2.goto('http://localhost:10000/', { waitUntil: 'domcontentloaded' });
    const stored = await page2.evaluate(() => {
      try { return localStorage.getItem('theme'); } catch { return null; }
    });
    // Fresh context should have no stored preference
    expect(stored).toBeNull();
    await context2.close();
  });

  test('localStorage persists through multiple tabs (same origin)', async ({ context }) => {
    // Set dark in tab 1
    const page1 = await context.newPage();
    await page1.goto('/', { waitUntil: 'domcontentloaded' });
    await page1.evaluate(() => { try { localStorage.setItem('theme', 'dark'); } catch {} });

    // Open tab 2 — should pick up dark preference from localStorage
    const page2 = await context.newPage();
    await page2.goto('/', { waitUntil: 'domcontentloaded' });
    const stored = await page2.evaluate(() => {
      try { return localStorage.getItem('theme'); } catch { return null; }
    });
    expect(stored).toBe('dark');

    await page1.close();
    await page2.close();
  });
});

// ============================================================
// 10. Visual Screenshots (dark & light across browsers)
// ============================================================
test.describe('Theme: Visual Snapshots', () => {

  const SNAPSHOT_PAGES = [
    { name: 'home', url: '/' },
    { name: 'about', url: '/about' },
    { name: 'services', url: '/services' },
    { name: 'contact', url: '/contact' },
  ];

  for (const p of SNAPSHOT_PAGES) {
    test(`Dark mode screenshot: ${p.name}`, async ({ page, browserName }) => {
      await page.setViewportSize({ width: 1280, height: 800 });
      await loadPageWithStoredTheme(page, 'dark');
      await page.goto(p.url, { waitUntil: 'domcontentloaded' });
      await page.waitForTimeout(500);

      await page.screenshot({
        path: `tests/screenshots/${browserName}-${p.name}-dark.png`,
        fullPage: false,
        clip: { x: 0, y: 0, width: 1280, height: 800 },
      });
    });

    test(`Light mode screenshot: ${p.name}`, async ({ page, browserName }) => {
      await page.setViewportSize({ width: 1280, height: 800 });
      await loadPageWithStoredTheme(page, 'light');
      await page.goto(p.url, { waitUntil: 'domcontentloaded' });
      await page.waitForTimeout(500);

      await page.screenshot({
        path: `tests/screenshots/${browserName}-${p.name}-light.png`,
        fullPage: false,
        clip: { x: 0, y: 0, width: 1280, height: 800 },
      });
    });
  }
});
