#!/usr/bin/env python3
"""Backfill images for existing UAL project packages.

Reason: earlier runs downloaded HTML but skipped images because UAL serves images from cloudinary/S3.

This script:
- Iterates project dirs under a year root
- Parses 00_source_page/page.html
- Extracts <main> image URLs (prefers largest in srcset)
- Downloads into 02_images/originals/img_###.ext
- Respects polite delay (default 10s + jitter)

Usage:
  source .venv_rca/bin/activate
  python tools/ual_backfill_images.py --root ~/Desktop/UAL_MediaLibrary/ual-showcase/2025 --limit 50
  python tools/media_onepager.py --root ~/Desktop/UAL_MediaLibrary/ual-showcase/2025
"""

import argparse
import os
import random
import re
import time
from pathlib import Path
from urllib.parse import urljoin, urlparse

import requests
from bs4 import BeautifulSoup

UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0 Safari/537.36"


def choose_best_src(img_tag):
    srcset = img_tag.get("srcset")
    if srcset:
        cands = []
        for part in srcset.split(","):
            part = part.strip()
            if not part:
                continue
            bits = part.split()
            u = bits[0]
            w = 0
            if len(bits) > 1:
                m = re.match(r"(\d+)(w|x)", bits[1])
                if m:
                    w = int(m.group(1))
            cands.append((w, u))
        cands.sort(key=lambda x: x[0], reverse=True)
        return cands[0][1] if cands else None
    return img_tag.get("src")


def polite_sleep(delay: float, jitter: float):
    time.sleep(delay + random.uniform(0, jitter))


def fetch(session: requests.Session, url: str, out: Path, timeout: int = 80):
    r = session.get(url, timeout=timeout)
    r.raise_for_status()
    out.write_bytes(r.content)


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--root", required=True, help="year root, e.g. .../ual-showcase/2025")
    ap.add_argument("--delay", type=float, default=10.0)
    ap.add_argument("--jitter", type=float, default=4.0)
    ap.add_argument("--limit", type=int, default=0, help="0=all")
    args = ap.parse_args()

    root = Path(os.path.expanduser(args.root)).resolve()
    projects_dir = root / "projects"
    assert projects_dir.exists(), f"missing {projects_dir}"

    session = requests.Session()
    session.headers.update({"User-Agent": UA})

    done = 0
    for proj in sorted([p for p in projects_dir.iterdir() if p.is_dir()]):
        page = proj / "00_source_page" / "page.html"
        if not page.exists():
            continue
        originals = proj / "02_images" / "originals"
        originals.mkdir(parents=True, exist_ok=True)

        # Skip if already has images
        existing = list(originals.glob("img_*"))
        if existing:
            continue

        html = page.read_bytes()
        soup = BeautifulSoup(html, "html.parser")
        main_el = soup.find("main") or soup.body or soup
        imgs = []
        for img in main_el.find_all("img"):
            u = choose_best_src(img)
            if not u:
                continue
            u = urljoin("https://ualshowcase.arts.ac.uk/", u)
            imgs.append(u)

        # uniq
        seen = set(); uniq = []
        for u in imgs:
            if u in seen:
                continue
            seen.add(u)
            uniq.append(u)

        for i, u in enumerate(uniq[:80], start=1):
            ext = os.path.splitext(urlparse(u).path)[1].lower()
            if ext not in {".jpg", ".jpeg", ".png", ".webp", ".gif"}:
                ext = ".jpg"
            out = originals / f"img_{i:03d}{ext}"
            if out.exists():
                continue
            try:
                fetch(session, u, out)
            except Exception:
                # skip broken
                continue
            polite_sleep(args.delay, args.jitter)

        done += 1
        if args.limit and done >= args.limit:
            break


if __name__ == "__main__":
    main()
