#!/usr/bin/env python3
"""
render_deck.py — render a .pptx to per-slide PNGs for visual QA, cross-platform.

This is only for *previewing* a deck (so Claude can eyeball it). It is NOT needed
to build or open a deck. It auto-detects the OS:

  macOS    : Microsoft PowerPoint (AppleScript) -> PDF -> pdftoppm -> PNG   [tested]
  Windows  : Microsoft PowerPoint (COM via PowerShell) -> PNG               [needs a PC to verify]
  Linux/*  : LibreOffice (soffice --headless) -> PDF -> pdftoppm -> PNG     [needs Linux to verify]

Usage:
    python3 render_deck.py path/to/deck.pptx [out_dir]

Outputs slide-1.png, slide-2.png, ... (or Slide1.PNG... on Windows) into out_dir
(default: <deck_dir>/render).
"""
import sys, os, subprocess, shutil, tempfile, glob


def _pdftoppm(pdf, outdir):
    if not shutil.which("pdftoppm"):
        print(f"PDF written: {pdf}  (install poppler/`pdftoppm` to get PNGs)")
        return
    subprocess.run(["pdftoppm", "-png", "-r", "110", pdf, os.path.join(outdir, "slide")], check=True)
    pngs = sorted(glob.glob(os.path.join(outdir, "slide-*.png")))
    print(f"OK  {len(pngs)} PNG(s) -> {outdir}")


def render_macos(pptx, outdir):
    pdf = os.path.join(outdir, "deck.pdf")
    scpt = ('on run\n'
            '  with timeout of 540 seconds\n'
            '    tell application "Microsoft PowerPoint"\n'
            '      activate\n'
            '      try\n        close every presentation saving no\n      end try\n'
            f'      open POSIX file "{pptx}"\n'
            '      set d to active presentation\n'
            f'      save d in (POSIX file "{pdf}") as save as PDF\n'
            '      close d saving no\n'
            '    end tell\n'
            '  end timeout\n'
            'end run\n')
    fd, path = tempfile.mkstemp(suffix=".scpt"); os.close(fd)
    with open(path, "w") as f:
        f.write(scpt)
    try:
        subprocess.run(["osascript", path], check=True)
    finally:
        os.remove(path)
    _pdftoppm(pdf, outdir)


def render_windows(pptx, outdir):
    # Microsoft PowerPoint COM. Export() writes Slide1.PNG, Slide2.PNG, ... into outdir.
    ps = ('$ErrorActionPreference = "Stop"\n'
          '$ppt = New-Object -ComObject PowerPoint.Application\n'
          f'$pres = $ppt.Presentations.Open("{pptx}", $true, $false, $false)\n'
          f'$pres.Export("{outdir}", "PNG")\n'
          '$pres.Close()\n'
          '$ppt.Quit()\n')
    fd, path = tempfile.mkstemp(suffix=".ps1"); os.close(fd)
    with open(path, "w") as f:
        f.write(ps)
    try:
        subprocess.run(["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", path], check=True)
        pngs = sorted(glob.glob(os.path.join(outdir, "*.PNG")) + glob.glob(os.path.join(outdir, "*.png")))
        print(f"OK  {len(pngs)} PNG(s) -> {outdir}")
    finally:
        os.remove(path)


def render_soffice(pptx, outdir):
    soffice = shutil.which("libreoffice") or shutil.which("soffice")
    if not soffice:
        print("No LibreOffice/soffice on PATH. Install it, or open the .pptx in PowerPoint.")
        return
    subprocess.run([soffice, "--headless", "--convert-to", "pdf", "--outdir", outdir, pptx], check=True)
    pdf = os.path.join(outdir, os.path.splitext(os.path.basename(pptx))[0] + ".pdf")
    _pdftoppm(pdf, outdir)


def main():
    if len(sys.argv) < 2:
        print(__doc__); sys.exit(1)
    pptx = os.path.abspath(sys.argv[1])
    outdir = os.path.abspath(sys.argv[2]) if len(sys.argv) > 2 else os.path.join(os.path.dirname(pptx), "render")
    os.makedirs(outdir, exist_ok=True)
    if sys.platform == "darwin":
        render_macos(pptx, outdir)
    elif sys.platform.startswith("win"):
        render_windows(pptx, outdir)
    else:
        render_soffice(pptx, outdir)


if __name__ == "__main__":
    main()
