#!/usr/bin/env python3
"""make_gallery.py — fetch actor images for a movie and build gallery.h5.

Fetches the cast from TMDB, downloads actor profile images, embeds them via
the sae_embed module (SCRFD + ArcFace, same models as scene_analyze, loaded
once), then writes gallery.h5.

Requirements:
    pip install requests Pillow

Usage:
    # By IMDB movie ID (most natural — resolves to TMDB automatically):
    python scripts/make_gallery.py \\
        --tmdb-key YOUR_KEY \\
        --imdb-id tt0137523 \\
        --output gallery.h5

    # Or directly with a TMDB movie ID:
    python scripts/make_gallery.py \\
        --tmdb-key YOUR_KEY \\
        --movie-id 550 \\
        --output gallery.h5

    # Additional options:
    #   --build-dir build/             build dir containing sae_embed module
    #   --models-dir models/            directory with ONNX models
    #   --images-per-actor 3            profile images to download per actor
    #   --image-dir /tmp/gallery_imgs   where to cache downloaded images

Get a free TMDB API key at: https://www.themoviedb.org/settings/api
"""

import argparse
import sys
import time
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
from sae_embed_loader import load_embedder, resolve_arcface
from sae_gallery import (download_images, embedder_stamp, save_gallery,
                         wikidata_image_urls)
from sae_tmdb import TMDB_IMG, tmdb_get, tmdb_id_from_imdb


def fetch_cast(movie_id: int, key: str) -> list[dict]:
    """Return list of {id, name, imdb_id, profile_images: [...url...]}."""
    credits = tmdb_get(f"/movie/{movie_id}/credits", key)
    cast = credits.get("cast", [])

    actors = []
    for member in cast:
        person_id = member["id"]

        # Get IMDB ID for this person
        ext = tmdb_get(f"/person/{person_id}/external_ids", key)
        imdb_id = ext.get("imdb_id") or ""

        # Get profile images (sorted by vote_average desc by TMDB)
        images_data = tmdb_get(f"/person/{person_id}/images", key)
        profiles = images_data.get("profiles", [])
        image_urls = [TMDB_IMG + p["file_path"] for p in profiles if p.get("file_path")]

        if not image_urls:
            image_urls = wikidata_image_urls(imdb_id)
            if image_urls:
                print(f"  [info] no TMDB images for {member['name']}, "
                      f"found {len(image_urls)} via Wikidata", file=sys.stderr)

        if not image_urls:
            print(f"  [warn] no images for {member['name']}", file=sys.stderr)

        actors.append({
            "id":            person_id,
            "name":          member["name"],
            "imdb_id":       imdb_id,
            "tmdb_id":       str(person_id),
            "profile_images": image_urls,
        })
        time.sleep(0.05)  # be polite to TMDB

    return actors


# ── Gallery assembly ─────────────────────────────────────────────────────────

def build_gallery(movie_id: int, key: str, embedder,
                  images_per_actor: int,
                  image_root: Path) -> tuple[dict, list[dict]]:
    """Fetch cast, download images, embed, return (gallery dict, actors needing more images)."""
    print(f"Fetching cast for TMDB movie {movie_id}…", file=sys.stderr)
    actors = fetch_cast(movie_id, key)
    print(f"Found {len(actors)} cast member(s)", file=sys.stderr)

    gallery_actors = []
    missing        = []

    for actor in actors:
        safe_name = actor["name"].replace(" ", "_")
        dir_id    = actor["imdb_id"] or f"tmdb_{actor['tmdb_id']}"
        actor_dir = image_root / f"{dir_id}_{safe_name}"

        print(f"\n{actor['name']} ({dir_id})", file=sys.stderr)

        if not actor["profile_images"]:
            print("  no images found, skipping", file=sys.stderr)
            missing.append({"name": actor["name"], "imdb_id": actor["imdb_id"],
                             "tmdb_id": actor["tmdb_id"], "reason": "no images found"})
            continue

        image_paths = download_images(actor["profile_images"], actor_dir, images_per_actor)
        if not image_paths:
            print("  no images downloaded, skipping", file=sys.stderr)
            missing.append({"name": actor["name"], "imdb_id": actor["imdb_id"],
                             "tmdb_id": actor["tmdb_id"], "reason": "download failed"})
            continue

        print(f"  embedding {len(image_paths)} image(s)…", file=sys.stderr)

        embeddings    = []
        source_images = []
        for path in image_paths:
            res = embedder.embed(str(path))
            if not res.ok:
                print(f"  [skip] {path.name}: {res.error}", file=sys.stderr)
                continue
            embeddings.append(res.embedding)
            source_images.append(path.name)
            print(f"  [ok]   {path.name}  conf={res.confidence:.2f}",
                  file=sys.stderr)

        if not embeddings:
            print("  no valid embeddings, skipping actor", file=sys.stderr)
            missing.append({"name": actor["name"], "imdb_id": actor["imdb_id"],
                             "tmdb_id": actor["tmdb_id"], "reason": "no valid embeddings"})
            continue

        gallery_actors.append({
            "imdb_id":      actor["imdb_id"],
            "tmdb_id":      actor["tmdb_id"],
            "jellyfin_id":  "",
            "name":         actor["name"],
            "source_images": source_images,
            "embeddings":   embeddings,
        })
        print(f"  → {len(embeddings)} embedding(s) stored", file=sys.stderr)

    return {"actors": gallery_actors}, missing


# ── Entry point ───────────────────────────────────────────────────────────────

def main():
    parser = argparse.ArgumentParser(
        description="Fetch TMDB cast images and build gallery.h5 via sae_embed")
    parser.add_argument("--tmdb-key",  required=True,
                        help="TMDB Bearer token (API Read Access Token from themoviedb.org/settings/api)")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("--imdb-id",
                        help="IMDB movie ID, e.g. tt0137523 — looked up via TMDB automatically")
    group.add_argument("--movie-id",  type=int,
                        help="TMDB movie ID (alternative to --imdb-id)")
    parser.add_argument("--output",          required=True,  help="Output gallery.h5 path")
    parser.add_argument("--build-dir",       default="build",
                        help="Build directory containing the sae_embed module (default: build)")
    parser.add_argument("--models-dir",      default="models",
                        help="Directory containing ONNX models (default: models/)")
    parser.add_argument("--arcface",         default=None,
                        help="Path to ArcFace ONNX model (overrides --models-dir selection)")
    parser.add_argument("--images-per-actor",type=int, default=3,
                        help="Profile images to download per actor (default: 3)")
    parser.add_argument("--image-dir",       default=None,
                        help="Where to store downloaded images (default: <output_dir>/images)")
    parser.add_argument("--keep-images",     action="store_true",
                        help="Do not delete downloaded images after embedding")
    args = parser.parse_args()

    # Resolve paths
    output     = Path(args.output)
    image_root = Path(args.image_dir) if args.image_dir else output.parent / "images"

    # TRACES: GR-004 | SR-001
    # stamp with the model actually loaded, resolved
    # through the same helper load_embedder uses so the two cannot diverge.
    arcface_path = resolve_arcface(args.models_dir, args.arcface)
    embedder = load_embedder(args.build_dir, args.models_dir, args.arcface)
    stamp = embedder_stamp(arcface_path)

    # Resolve movie ID
    movie_id = args.movie_id
    if movie_id is None:
        print(f"Resolving IMDB ID {args.imdb_id} → TMDB…", file=sys.stderr)
        movie_id = tmdb_id_from_imdb(args.imdb_id, args.tmdb_key)
        print(f"TMDB movie ID: {movie_id}", file=sys.stderr)

    # Build gallery
    gallery, missing = build_gallery(
        movie_id      = movie_id,
        key           = args.tmdb_key,
        embedder      = embedder,
        images_per_actor = args.images_per_actor,
        image_root    = image_root,
    )

    n_actors     = len(gallery["actors"])
    n_embeddings = sum(len(a["embeddings"]) for a in gallery["actors"])
    print(f"\nGallery: {n_actors} actors, {n_embeddings} total embeddings",
          file=sys.stderr)

    if n_actors == 0:
        sys.exit("No actors could be processed — check models and images.")

    save_gallery(gallery, missing, output, embedder=stamp)


if __name__ == "__main__":
    main()
