#!/usr/bin/env python3
"""
wash_mj_heroes.py — Wash MJ hero images through NBP for photorealistic conversion.

ADR-M05: MJ illustrations need "washing" to strip stylized textures and convert
to photorealistic rendering before they become permanent identity refs.

Uses NBP (Gemini 3 Pro) at temperature 0.4 for tight adherence to facial structure.
JT must approve washed versions before they replace originals.

Usage:
    python -m tools.wash_mj_heroes --dry-run
    python -m tools.wash_mj_heroes --character JINX --input path/to/mj_hero.png --project tartarus
    python -m tools.wash_mj_heroes --character JINX --input path/to/mj_hero.png
"""

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

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

from recoil.core.paths import PIPELINE_ROOT  # noqa: F401
from recoil.core.model_profiles import get_model
from recoil.core.prompt_config import get_constant

NBP_MODEL = get_model("production", "image")
NBP_COST = 0.134


def _build_wash_prompt() -> str:
    """Build the MJ wash prompt from prompt_config casting constants."""
    camera = get_constant("casting", "casting_camera")
    background = get_constant("casting", "casting_background")
    texture = get_constant("casting", "casting_texture_human")
    anti_airbrush = get_constant("casting", "casting_anti_airbrush")

    return (
        f"Diegetic frame: {texture} Recreate this exact "
        f"person's facial structure, haircut, and features perfectly. "
        f"Photographic reality, {camera} lens, {background}. "
        f"{anti_airbrush} Render as a living human actor standing "
        f"on a movie set with cinematic lighting."
    )


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


def wash_hero(
    character: str,
    input_path: Path,
    dry_run: bool = False,
) -> Optional[dict]:
    """Wash a single MJ hero image through NBP.

    Args:
        character: Character ID (e.g. JINX).
        input_path: Path to MJ hero image.
        dry_run: If True, show prompt without API call.

    Returns:
        Dict with {character, input, output, cost} or None on failure.
    """
    if not input_path.exists():
        logger.error(f"Input image not found: {input_path}")
        return None

    # Output goes alongside the original with _washed suffix
    stem = input_path.stem
    ext = input_path.suffix
    output_path = input_path.parent / f"{stem}_washed{ext}"

    if output_path.exists():
        logger.info(f"  Washed version already exists: {output_path}")
        return {"character": character, "input": str(input_path), "output": str(output_path), "cost": 0}

    if dry_run:
        logger.info(f"  [DRY RUN] {character}: Would wash {input_path.name}")
        logger.info(f"  [DRY RUN] Prompt: {_build_wash_prompt()[:100]}...")
        logger.info(f"  [DRY RUN] Output: {output_path}")
        return {"character": character, "input": str(input_path), "output": None, "cost": 0}

    # Call NBP with MJ image + wash prompt
    washed_bytes = _generate_nbp_wash(input_path)
    if washed_bytes is None:
        logger.error(f"  Wash failed for {character}")
        return None

    output_path.write_bytes(washed_bytes)
    logger.info(f"  Washed: {output_path} ({len(washed_bytes) / 1024:.0f} KB)")
    logger.info(f"  ** JT must approve before this becomes a permanent identity ref **")

    return {
        "character": character,
        "input": str(input_path),
        "output": str(output_path),
        "cost": NBP_COST,
    }


def _generate_nbp_wash(input_path: Path) -> Optional[bytes]:
    """Generate washed version via NBP at temperature 0.4."""
    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)

    # Load MJ hero image
    image_bytes = input_path.read_bytes()
    mime = "image/jpeg" if input_path.suffix.lower() in (".jpg", ".jpeg") else "image/png"

    parts = [
        types.Part.from_bytes(data=image_bytes, mime_type=mime),
        types.Part(text="[CHARACTER REFERENCE — RECREATE EXACTLY]"),
        types.Part(text=_build_wash_prompt()),
    ]

    try:
        response = client.models.generate_content(
            model=NBP_MODEL,
            contents=parts,
            config=types.GenerateContentConfig(
                temperature=0.4,  # Low temp for tight adherence
                response_modalities=["IMAGE", "TEXT"],
                image_config=types.ImageConfig(
                    aspect_ratio="9:16",
                ),
            ),
        )
    except Exception as e:
        logger.error(f"NBP 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="Wash MJ hero images through NBP for photorealistic conversion (ADR-M05)"
    )
    parser.add_argument("--character", required=False, help="Character ID (e.g. JINX)")
    parser.add_argument("--input", required=False, help="Path to MJ hero image")
    parser.add_argument("--project", default=None, help="Project name")
    parser.add_argument("--dry-run", action="store_true")
    args = parser.parse_args()

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

    if args.character and args.input:
        result = wash_hero(
            character=args.character,
            input_path=Path(args.input).expanduser(),
            dry_run=args.dry_run,
        )
        if result:
            cost = result.get("cost", 0)
            print(f"\nDone: {result.get('output', '(dry run)')}, ${cost:.3f}")
        else:
            print("\nFailed.")
            sys.exit(1)
    else:
        if args.dry_run:
            print("[DRY RUN] No --character or --input specified.")
            print("Usage: python -m tools.wash_mj_heroes --character JINX --input path/to/hero.png")
            print("Would wash MJ illustrations → photorealistic via NBP ($0.134/image)")
        else:
            parser.print_help()


if __name__ == "__main__":
    main()
