#!/usr/bin/env python3
"""
prep_prop_refs.py — Generate prop turnaround sheets and slice into 3-view refs.

Reads GlobalBible props and generates turnaround sheets via Flash 3.1 ($0.039).
PIL slices each turnaround into 3 equal panels: front, side, 3/4 angle.

Output: assets/prop/{prop_id}/{prop_id}_{state}_front.png, _side.png, _3q.png (via asset_subject_dir)
These are consumed by AssetManager.get_prop_ref() at weight 7-8.

Supports multi-state generation: for each prop with states dict, generates
a turnaround per state. Props without states get a single "default" turnaround.

ADR-P01: Dedicated prop reference images (turnaround sheets, 3-view, PIL slice).

Usage:
    python -m tools.prep_prop_refs --dry-run
    python -m tools.prep_prop_refs --project tartarus
    python -m tools.prep_prop_refs --project tartarus --prop salvage_hook
"""

import argparse
import json
import logging
import os
import sys
import time
from pathlib import Path
from typing import Optional

sys.path.insert(0, str(Path(__file__).parent.parent))

from recoil.core.paths import ProjectPaths
from recoil.core.model_profiles import get_model
FLASH_MODEL = get_model("exploration", "image")
FLASH_COST = 0.039

PROP_TURNAROUND_PROMPT = (
    "Diegetic frame: VFX asset turnaround sheet. A single wide image containing three distinct "
    "side-by-side views (Front, Side, 3/4 angle) of the exact same object: {description}. "
    "{state_note}"
    "High-end prop master craftsmanship, hyper-detailed textures. Isolated on a flat 18% neutral "
    "gray background. Studio lighting, macro lens."
)

logger = logging.getLogger("starsend.prep_prop_refs")


def generate_prop_refs(
    bible: dict,
    project: Optional[str] = None,
    dry_run: bool = False,
    prop_filter: Optional[str] = None,
) -> list:
    """Generate turnaround sheets for all props and slice into 3-view refs.

    Args:
        bible: Global bible dict.
        project: Project name (for logging).
        dry_run: If True, log prompts but don't call API.
        prop_filter: If set, only process this prop_id.

    Returns:
        List of dicts: [{prop_id, state, views: [path, ...], cost}]
    """
    props = bible.get("props", {})
    if not props:
        logger.warning("No props in bible")
        return []

    results = []

    for prop_id, prop_data in props.items():
        if prop_filter and prop_id != prop_filter:
            continue

        description = prop_data.get("description", prop_id)
        states = prop_data.get("states", {})

        # If no states defined, generate a single "default" turnaround
        if not states:
            states = {"default": description}

        for state_id, state_desc in states.items():
            subject_root = ProjectPaths.for_project(project).asset_subject_dir("prop", prop_id)
            front_path = subject_root / f"{prop_id}_{state_id}_front.png"

            # Skip if already sliced
            if front_path.exists():
                logger.info(f"  Skipping {prop_id}/{state_id} (refs exist)")
                continue

            state_note = f"State: {state_desc}. " if state_id != "default" else ""
            prompt = PROP_TURNAROUND_PROMPT.format(
                description=description,
                state_note=state_note,
            )

            if dry_run:
                logger.info(f"  [DRY RUN] {prop_id}/{state_id}: {prompt[:120]}...")
                results.append({
                    "prop_id": prop_id,
                    "state": state_id,
                    "views": [],
                    "cost": 0,
                })
                continue

            # Generate turnaround sheet
            turnaround_bytes = _generate_flash_image(prompt)
            if turnaround_bytes is None:
                logger.warning(f"  Failed: {prop_id}/{state_id}")
                continue

            # Save full turnaround
            subject_root.mkdir(parents=True, exist_ok=True)
            turnaround_path = subject_root / f"{prop_id}_{state_id}_turnaround.png"
            turnaround_path.write_bytes(turnaround_bytes)
            logger.info(f"  Turnaround saved: {turnaround_path}")

            # Slice into 3 panels
            view_paths = _slice_turnaround(turnaround_path, prop_id, state_id)

            results.append({
                "prop_id": prop_id,
                "state": state_id,
                "views": [str(p) for p in view_paths],
                "cost": FLASH_COST,
            })

            time.sleep(2)  # Rate limit

    total_cost = sum(r["cost"] for r in results)
    logger.info(f"Prop refs complete: {len(results)} turnarounds, ${total_cost:.3f}")
    return results


def _slice_turnaround(turnaround_path: Path, prop_id: str, state_id: str) -> list:
    """Slice a turnaround sheet into 3 equal vertical panels: front, side, 3q."""
    try:
        from PIL import Image
    except ImportError:
        logger.warning("PIL not available — cannot slice turnaround")
        return []

    img = Image.open(turnaround_path)
    w, h = img.size
    third = w // 3

    view_names = ["front", "side", "3q"]
    panels = [
        img.crop((0, 0, third, h)),
        img.crop((third, 0, third * 2, h)),
        img.crop((third * 2, 0, w, h)),
    ]

    prop_dir = turnaround_path.parent
    paths = []
    for name, panel in zip(view_names, panels):
        panel_path = prop_dir / f"{prop_id}_{state_id}_{name}.png"
        panel.save(panel_path)
        paths.append(panel_path)

    logger.info(f"  Sliced into {len(paths)} views")
    return paths


def _generate_flash_image(prompt: str) -> Optional[bytes]:
    """Generate one image via Flash 3.1 (16:9 landscape for turnaround layout)."""
    try:
        from google import genai
        from google.genai import types
    except ImportError:
        logger.error("google-genai SDK not installed")
        return None

    api_key = os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY")
    if not api_key:
        logger.error("GEMINI_API_KEY not set")
        return None

    client = genai.Client(api_key=api_key)

    try:
        response = client.models.generate_content(
            model=FLASH_MODEL,
            contents=[types.Part(text=prompt)],
            config=types.GenerateContentConfig(
                response_modalities=["IMAGE", "TEXT"],
                image_config=types.ImageConfig(
                    aspect_ratio="16:9",  # Wide for 3-panel turnaround
                ),
            ),
        )
    except Exception as e:
        logger.error(f"Flash API error: {e}")
        return None

    if response and response.candidates:
        for candidate in response.candidates:
            if candidate.content and candidate.content.parts:
                for part in candidate.content.parts:
                    if hasattr(part, "inline_data") and part.inline_data:
                        return part.inline_data.data

    return None


def main():
    parser = argparse.ArgumentParser(
        description="Generate prop turnaround sheets and 3-view refs (ADR-P01)"
    )
    parser.add_argument("--dry-run", action="store_true")
    parser.add_argument("--project", default=None)
    parser.add_argument("--prop", default=None, help="Only process this prop_id")
    args = parser.parse_args()

    logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%H:%M:%S")

    # Load bible — project-scoped, no engine-default fallback (fail loud).
    if not args.project:
        sys.exit("ERROR: --project is required (no engine-default bible fallback).")
    bible_path = ProjectPaths.for_project(args.project).global_bible_path

    if not bible_path.exists():
        print(f"ERROR: Global bible not found at {bible_path}")
        print("Run Stage 1 (breakdown pass) first.")
        sys.exit(1)

    bible = json.loads(bible_path.read_text(encoding="utf-8"))

    results = generate_prop_refs(
        bible, project=args.project, dry_run=args.dry_run, prop_filter=args.prop,
    )

    total_cost = sum(r["cost"] for r in results)
    print(f"\nDone: {len(results)} turnarounds, ${total_cost:.3f}")


if __name__ == "__main__":
    main()
