#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# ///
"""Measure every slide against the 720px frame, and screenshot them.

Why this exists: slides clip silently. `.slide` is a fixed 1280x720 box with
`overflow: hidden`, so content that runs past the bottom simply vanishes -- no
scrollbar, no error, and it looks fine in the authoring loop. Two slides shipped
overflowing before this check existed, and the only reason anyone noticed was a
human squinting at a projector.

The measurement trick: clone the deck, force every slide to `height: auto` with
`overflow: visible`, and read back each natural height. Anything over 720 would
have been clipped, and by exactly the reported amount.

Aim for 690 or less. A slide at 715 fits on this machine and may clip on another,
because font rasterisation differs between platforms and a few pixels of line-box
rounding is all it takes.

Usage:
  uv run audit_deck.py <deck.html> [--shots 1,3,5] [--outdir DIR]

Requires a Chrome or Chromium binary. On WSL2 it finds the Windows Chrome, since
Ubuntu's `chromium-browser` is often a snap stub that cannot run at all.
"""

import argparse
import re
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path

FRAME_HEIGHT = 720
COMFORTABLE = 690

AUDIT_SNIPPET = """<script>
window.addEventListener('load', function () {
  var out = [];
  var slides = document.querySelectorAll('.slide');
  slides.forEach(function (s) {
    s.style.display = 'flex';
    s.style.height = 'auto';
    s.style.overflow = 'visible';
    s.style.transform = 'none';
    s.style.position = 'relative';
  });
  slides.forEach(function (s, i) {
    out.push(i + ':' + Math.round(s.getBoundingClientRect().height));
  });
  document.title = 'AUDIT ' + out.join(',');
});
</script>"""

CANDIDATES = [
    "/mnt/c/Program Files/Google/Chrome/Application/chrome.exe",
    "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
]

WINDOWS_TEMP = "/mnt/c/Windows/Temp"


def find_chrome() -> str:
    for name in ("google-chrome", "google-chrome-stable", "chromium", "chromium-browser"):
        path = shutil.which(name)
        if not path:
            continue
        # Ubuntu ships a snap stub at /usr/bin/chromium-browser that only prints an
        # install hint, so confirm the binary actually answers --version.
        probe = subprocess.run([path, "--version"], capture_output=True, text=True)
        if probe.returncode == 0 and "snap" not in probe.stdout.lower():
            return path
    for path in CANDIDATES:
        if Path(path).exists():
            return path
    raise SystemExit("error: no usable Chrome or Chromium found")


def is_windows_chrome(chrome: str) -> bool:
    return chrome.endswith(".exe")


def to_url(path: Path, chrome: str, staging: Path | None) -> str:
    """Windows Chrome cannot read a WSL path, so serve it a copy under /mnt/c."""
    if not is_windows_chrome(chrome):
        return f"file://{path}"
    target = staging / path.name
    shutil.copy(path, target)
    win = subprocess.run(["wslpath", "-w", str(target)], capture_output=True, text=True, check=True)
    return "file:///" + win.stdout.strip().replace("\\", "/")


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("deck")
    parser.add_argument("--shots", help="1-indexed slides to screenshot, e.g. 1,3,5")
    parser.add_argument("--outdir", default="deck-audit", help="Where screenshots land")
    args = parser.parse_args()

    deck = Path(args.deck).resolve()
    chrome = find_chrome()
    print(f"browser: {chrome}")

    # Windows Chrome cannot read a WSL path, so it gets a staging copy on a drive
    # it can see. Only that branch needs the Windows temp directory, so check the
    # directory exists rather than assuming: this runs on whatever WSL2 setup the
    # operator has, and a missing path here should say so plainly.
    if is_windows_chrome(chrome):
        win_temp = Path(WINDOWS_TEMP)
        if not win_temp.is_dir():
            raise SystemExit(
                f"error: {WINDOWS_TEMP} is not reachable, so Windows Chrome has\n"
                "nowhere to read the deck from. Install a Linux Chrome or Chromium\n"
                "instead, or mount the Windows drive."
            )
        staging_ctx = tempfile.TemporaryDirectory(dir=win_temp)
    else:
        staging_ctx = tempfile.TemporaryDirectory()

    with staging_ctx as staging_name, tempfile.TemporaryDirectory() as work:
        staging = Path(staging_name)
        source = deck.read_text(encoding="utf-8")
        probe = Path(work) / "audit.html"
        probe.write_text(source.replace("</body>", AUDIT_SNIPPET + "</body>"), encoding="utf-8")

        result = subprocess.run(
            [chrome, "--headless", "--disable-gpu", "--no-sandbox",
             "--virtual-time-budget=9000", "--dump-dom",
             to_url(probe, chrome, staging)],
            capture_output=True, text=True,
        )
        found = re.search(r"AUDIT ([0-9:,]+)", result.stdout)
        if not found:
            print("error: the audit script did not run; is the deck valid HTML?", file=sys.stderr)
            return 1

        heights = [int(pair.split(":")[1]) for pair in found.group(1).split(",")]
        over = []
        print(f"\n{len(heights)} slides, frame is {FRAME_HEIGHT}px:\n")
        for i, h in enumerate(heights):
            if h > FRAME_HEIGHT:
                verdict, mark = f"CLIPPED by {h - FRAME_HEIGHT}px", "x"
                over.append(i + 1)
            elif h > COMFORTABLE:
                verdict, mark = f"tight, only {FRAME_HEIGHT - h}px spare", "!"
            else:
                verdict, mark = f"ok, {FRAME_HEIGHT - h}px spare", " "
            print(f"  {mark} slide {i + 1:>2}  {h:>4}px  {verdict}")

        if args.shots:
            outdir = Path(args.outdir)
            outdir.mkdir(parents=True, exist_ok=True)
            for n in [s.strip() for s in args.shots.split(",")]:
                shot = staging / f"slide{n}.png" if is_windows_chrome(chrome) else outdir / f"slide{n}.png"
                win_shot = shot
                if is_windows_chrome(chrome):
                    win_shot = subprocess.run(["wslpath", "-w", str(shot)],
                                              capture_output=True, text=True, check=True).stdout.strip()
                subprocess.run(
                    [chrome, "--headless", "--disable-gpu", "--no-sandbox", "--hide-scrollbars",
                     "--window-size=1280,720", "--virtual-time-budget=8000",
                     f"--screenshot={win_shot}",
                     to_url(deck, chrome, staging) + f"#{n}"],
                    capture_output=True,
                )
                if is_windows_chrome(chrome) and shot.exists():
                    shutil.copy(shot, outdir / f"slide{n}.png")
            print(f"\nscreenshots in {outdir}/ -- open them, do not assume they are right")

        if over:
            print(f"\nFAIL: slides {over} are clipped. Cut content or tighten that slide's rhythm.")
            return 1
        print("\nAll slides fit.")
        return 0


if __name__ == "__main__":
    raise SystemExit(main())
