import os
import json
import time
import random
from pathlib import Path
from google import genai
from google.genai import types

GEMINI_API_KEY = os.environ["GEMINI_API_KEY"]
client = genai.Client(api_key=GEMINI_API_KEY)

# ─────────────────────────────────────────────────────────────────────────────
# ORDRE CRITIQUE : personnages EN PREMIER (0, 1), véhicules ensuite (2, 3),
# puis décors (4, 5).
# ─────────────────────────────────────────────────────────────────────────────
REFS = {
    # --- PERSONNAGES (Images 0, 1) ---
    "enfant":          "space_rocket.png",      # Image 0 -> {prenom} avec casque carton
    "zik":             "doudou.png",             # Image 1 -> Zik le chien-doudou
    # --- VÉHICULE (Images 2, 3) ---
    "fusee_chambre":   "fusée.png",              # Image 2 -> La Fusée dans la chambre
    "fusee_espace":    "bubble_rocket.png",      # Image 3 -> La Fusée dans l'espace
    # --- DÉCORS (Images 4, 5) ---
    "fruits":          "strawberry_planet.png",  # Image 4 -> La Ceinture des Fruits
    "station":         "star_planet.png",        # Image 5 -> La Station des Étoiles
}

CHARACTER_MAPPING = (
    "STRICT IDENTITY MAPPING — follow exactly: "
    "Character 1 (CHILD {prenom} WITH CARDBOARD HELMET) = Image 0. "
    "Character 2 (ZIK THE PLUSH DOG ASTRONAUT) = Image 1. "
    "Vehicle A (LA FUSEE in bedroom setting) = Image 2. "
    "Vehicle B (LA FUSEE in space setting) = Image 3. "
    "Background A (LA CEINTURE DES FRUITS — fruit planets) = Image 4. "
    "Background B (LA STATION DES ETOILES — crystal star station) = Image 5. "
)

LOCK_PHRASES = (
    "Maintain strict visual likeness of every character and vehicle as shown in their reference images. "
    "Ensure {prenom}'s cardboard helmet design, Zik's plush texture and bubble helmet, "
    "and La Fusee's handmade cardboard construction remain 100% identical to references. "
    "Do not alter character proportions, designs, or textures. "
)

IMAGE_DESCRIPTIONS = (
    "Image 0 = CHILD {prenom} WITH CARDBOARD HELMET: child with short wavy brown hair, big brown eyes, "
    "blue denim overalls over striped t-shirt, red sneakers. In space scenes wears a square cardboard box "
    "helmet decorated with drawn stars and rocket doodles, round porthole opening showing the face. "
    "Same design every scene. "
    "Image 1 = ZIK THE PLUSH DOG: fluffy light beige-brown plush stuffed dog, floppy ears, button eyes, "
    "embroidered nose, small tail, wearing a clear transparent round bubble astronaut helmet with a gold "
    "ring collar seal, star patch embroidered on chest. Same design every scene. "
    "Image 2 = LA FUSEE IN BEDROOM: large handmade cardboard rocket standing on a child's bedroom rug, "
    "pointed cone top, cylindrical body with hand-drawn stars and colorful rocket illustration, round "
    "porthole window, two cardboard fin wings, golden glitter trim on edges. Use for pages 1-3 and 15-16. "
    "Image 3 = LA FUSEE IN SPACE: same cardboard rocket flying through space, emitting golden magical "
    "exhaust trail, round porthole window with child visible inside. Use for all space flight scenes. "
    "Image 4 = LA CEINTURE DES FRUITS: magical deep space sector with giant fruit-shaped planets — "
    "enormous strawberry with green leaf top, orange planet with rings, banana-shaped comets, cherry "
    "planets — deep blue-purple starry space background. Use for pages 5-6. "
    "Image 5 = LA STATION DES ETOILES: enormous magnificent crystal star-shaped space station, "
    "faceted like a diamond in purple and blue iridescent crystal, golden spire on top, glowing "
    "internally with warm amber-purple light. Use for pages 8-10. "
)

PRENOM = "Leo"


def load_references():
    loaded = {}
    for name, path in REFS.items():
        if Path(path).exists():
            loaded[name] = Path(path).read_bytes()
            print(f"Reference chargee : {path}")
        else:
            loaded[name] = None
            print(f"Pas de reference : {path}")
    return loaded


def call_with_retry(parts, max_retries=5):
    for attempt in range(max_retries):
        try:
            return client.models.generate_content(
                model="gemini-3-pro-image-preview",
                contents=parts,
                config=types.GenerateContentConfig(
                    response_modalities=["IMAGE", "TEXT"]
                )
            )
        except Exception as e:
            wait = (2 ** attempt) + random.uniform(0, 2)
            print(f"Tentative {attempt + 1}/{max_retries} echouee : {e}")
            if attempt < max_retries - 1:
                print(f"Attente {wait:.1f}s avant retry...")
                time.sleep(wait)
            else:
                raise


def generate_page(page_data, style_master, refs, output_dir="pages_fusee"):
    Path(output_dir).mkdir(exist_ok=True)
    page_num = page_data["page"]
    page_type = page_data["type"]
    prompt = page_data["prompt"].replace("{prenom}", PRENOM)
    output_path = f"{output_dir}/page_{page_num:02d}.png"

    format_instruction = (
        "IMPORTANT: single full square illustration 2362x2362 pixels, no spread, no border, fills entire frame."
        if page_type == "simple"
        else "IMPORTANT: double page spread 4724x2362 pixels, 2:1 ratio, safe center fold, no spine line, fills entire frame."
    )

    full_prompt = style_master + " " + format_instruction + " Scene: " + prompt
    print(f"Page {page_num:02d}...")

    mapping = CHARACTER_MAPPING.replace("{prenom}", PRENOM)
    lock = LOCK_PHRASES.replace("{prenom}", PRENOM)
    descriptions = IMAGE_DESCRIPTIONS.replace("{prenom}", PRENOM)

    text = (
        mapping
        + lock
        + descriptions
        + "COSMO THE ROBOT: small boxy cardboard robot toy, brown cardboard body with drawn-on dials "
          "and buttons, small antenna on top, two round eyes made of bottle caps, friendly expression. "
        + "MAMAN: warm kind adult woman, short dark hair, loving playful expression, home clothes in "
          "bedroom scenes, appears pages 2, 7, 16. "
        + "Now generate: " + full_prompt
    )

    # Personnages en premier (0→1), véhicules (2→3), décors (4→5)
    parts = [types.Part(text=text)]
    for key in ["enfant", "zik", "fusee_chambre", "fusee_espace", "fruits", "station"]:
        if refs.get(key):
            parts.append(types.Part(
                inline_data=types.Blob(data=refs[key], mime_type="image/png")
            ))

    response = call_with_retry(parts)

    for part in response.candidates[0].content.parts:
        if part.inline_data:
            with open(output_path, "wb") as f:
                f.write(part.inline_data.data)
            print(f"OK : {output_path}")
            return output_path

    print(f"ERREUR page {page_num} : aucune image dans la reponse")
    return None


def generate_book(prompts_file="prompts_fusee.json", start_page=1, end_page=None):
    with open(prompts_file, "r", encoding="utf-8") as f:
        data = json.load(f)

    style_master = data["style_master"]
    pages = data["pages"]

    if end_page:
        pages = [p for p in pages if start_page <= p["page"] <= end_page]
    else:
        pages = [p for p in pages if p["page"] >= start_page]

    refs = load_references()

    print(f"Generation : {len(pages)} pages — prenom : {PRENOM}")
    results = []

    for page_data in pages:
        path = generate_page(page_data, style_master, refs)
        results.append({
            "page": page_data["page"],
            "path": path,
            "success": path is not None
        })
        time.sleep(5)

    success = sum(1 for r in results if r["success"])
    print(f"\nTermine : {success}/{len(pages)} pages generees")

    with open("book_fusee_results.json", "w") as f:
        json.dump(results, f, indent=2)

    return results


if __name__ == "__main__":
    import sys
    prompts_file = sys.argv[1] if len(sys.argv) > 1 else "prompts_fusee.json"
    start = int(sys.argv[2]) if len(sys.argv) > 2 else 1
    end = int(sys.argv[3]) if len(sys.argv) > 3 else None
    generate_book(prompts_file, start, end)
