#!/usr/bin/env python3
"""
Brief test 20 - the site renders correctly on mobile and desktop.

Development tool (NOT needed in production). Requires Python + Playwright:
    pip install playwright && playwright install chromium
Run against a running copy of the site:
    python3 tests/browser/render_check.py http://127.0.0.1:8088 [screenshot_dir]

For every page, at 1366px desktop and 390px mobile, it checks:
  - HTTP 200 and no horizontal scrolling (layout viewport == device width)
  - self-hosted Poppins is loaded (no Google Fonts)
  - no JavaScript errors and no Content-Security-Policy violations
  - template JS works under the CSP: mobile drawer opens, FAQ accordion toggles
Exit code 0 = all checks passed.
"""
import json
import sys

from playwright.sync_api import sync_playwright

BASE = (sys.argv[1] if len(sys.argv) > 1 else "http://127.0.0.1:8088").rstrip("/")
SHOTS = sys.argv[2] if len(sys.argv) > 2 else None
PAGES = ["/", "/awards", "/panel", "/results", "/about", "/contact", "/faq",
         "/voting-rules", "/terms", "/privacy", "/does-not-exist"]
VIEWPORTS = {
    "desktop": dict(viewport={"width": 1366, "height": 900}),
    "mobile": dict(viewport={"width": 390, "height": 844}, device_scale_factor=2, is_mobile=True, has_touch=True),
}
# Harmless template warning when a single hero slide exists.
IGNORED = ("Swiper Loop Warning",)

failures, results = [], {}

with sync_playwright() as p:
    browser = p.chromium.launch()
    for vp_name, opts in VIEWPORTS.items():
        ctx = browser.new_context(**opts)
        page = ctx.new_page()
        messages = []
        page.on("console", lambda m: messages.append(f"{m.type}: {m.text}"))
        page.on("pageerror", lambda e: messages.append(f"pageerror: {e}"))

        extra = []
        try:
            # Discover one award/category/nominee URL from the awards page, if any exist.
            page.goto(BASE + "/awards", wait_until="networkidle")
            award = page.eval_on_selector_all("a.pk-award-card", "els => els.map(e => new URL(e.href).pathname)")
            if award:
                extra.append(award[0])
                page.goto(BASE + award[0], wait_until="networkidle")
                cat = page.eval_on_selector_all("a.pk-category-card", "els => els.map(e => new URL(e.href).pathname)")
                if cat:
                    extra.append(cat[0])
                    page.goto(BASE + cat[0], wait_until="networkidle")
                    nom = page.eval_on_selector_all(".pk-nominee-card h3 a", "els => els.map(e => new URL(e.href).pathname)")
                    if nom:
                        extra.append(nom[0])
        except Exception as exc:  # noqa: BLE001
            failures.append(f"{vp_name}: discovery failed: {exc}")

        for path in PAGES + extra:
            messages.clear()
            response = page.goto(BASE + path, wait_until="networkidle")
            page.wait_for_timeout(500)
            page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
            page.wait_for_timeout(500)
            page.evaluate("window.scrollTo(0, 0)")
            status = response.status if response else 0
            layout = page.evaluate("() => [innerWidth, document.documentElement.scrollWidth]")
            poppins = page.evaluate("document.fonts.check('16px Poppins')")
            google = page.evaluate("[...document.querySelectorAll('link,script')].some(e => /googleapis|gstatic|cdn/i.test(e.href || e.src || ''))")
            problems = [m for m in messages if (m.startswith("error") or m.startswith("pageerror") or "Content Security Policy" in m)
                        and not any(i in m for i in IGNORED)]
            if path == "/does-not-exist":
                problems = [m for m in problems if "404" not in m]
                ok_status = status == 404
            else:
                ok_status = status == 200
            key = f"{vp_name} {path}"
            results[key] = {"status": status, "layout": layout, "poppins": poppins}
            if not ok_status:
                failures.append(f"{key}: HTTP {status}")
            if layout[1] > layout[0] + 1 or (vp_name == "mobile" and layout[0] != 390):
                failures.append(f"{key}: horizontal overflow {layout}")
            if not poppins:
                failures.append(f"{key}: Poppins not loaded")
            if google:
                failures.append(f"{key}: external font/CDN asset referenced")
            if problems:
                failures.append(f"{key}: console problems {problems}")
            if SHOTS:
                page.screenshot(path=f"{SHOTS}/{vp_name}{path.replace('/', '_') or '_home'}.png", full_page=False)

        # Template JavaScript still works under the CSP.
        page.goto(BASE + "/faq", wait_until="networkidle")
        page.click(".pk-accordion .item .q")
        if not page.evaluate("document.querySelector('.pk-accordion .item').classList.contains('open')"):
            failures.append(f"{vp_name}: FAQ accordion did not open")
        if vp_name == "mobile":
            page.goto(BASE + "/", wait_until="networkidle")
            page.click("#pkMenuToggle")
            page.wait_for_timeout(400)
            if not page.evaluate("document.querySelector('#pkNav').classList.contains('open')"):
                failures.append("mobile: navigation drawer did not open")
            if SHOTS:
                page.screenshot(path=f"{SHOTS}/mobile_menu_open.png")
        ctx.close()
    browser.close()

print(json.dumps(results, indent=1))
if failures:
    print("\nFAILURES:\n  " + "\n  ".join(failures))
    sys.exit(1)
print(f"\nOK: {len(results)} page renders checked on desktop and mobile, no failures.")
