#!/usr/bin/env python3
"""
THE BAKER — Deck Visual Generator

Generate visuals for pitch deck slides using the trained LoRA model.

Usage:
    source /home/workspaces/cultguard-agents/.devenv/state/venv/bin/activate
    python generate_deck_visual.py \
        --prompt "the baker film style, barakat estate interior, grandeur with decay" \
        --output assets/decks/visuals/estate.png \
        --lora outputs/lora_weights.safetensors
"""

import argparse
import logging
from pathlib import Path

import torch
from PIL import Image

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)


def load_pipeline(base_model: str, lora_path: str | None = None):
    """Load Flux pipeline with optional LoRA weights."""
    
    from diffusers import FluxPipeline
    
    logger.info(f"Loading Flux pipeline from {base_model}...")
    
    pipeline = FluxPipeline.from_pretrained(
        base_model,
        torch_dtype=torch.float16,
    ).to("cuda")
    
    if lora_path:
        logger.info(f"Loading LoRA weights from {lora_path}...")
        pipeline.load_lora_weights(lora_path)
    
    # Enable optimizations
    pipeline.enable_model_cpu_offload()
    pipeline.enable_vae_slicing()
    pipeline.enable_attention_slicing()
    
    return pipeline


def generate_visual(
    pipeline,
    prompt: str,
    output_path: str,
    negative_prompt: str = "",
    width: int = 1024,
    height: int = 1024,
    steps: int = 28,
    guidance: float = 3.5,
    seed: int | None = None,
) -> Image.Image:
    """Generate a single visual."""
    
    logger.info(f"Generating: {prompt[:80]}...")
    
    generator = None
    if seed is not None:
        generator = torch.Generator("cuda").manual_seed(seed)
    
    image = pipeline(
        prompt=prompt,
        negative_prompt=negative_prompt,
        num_inference_steps=steps,
        guidance_scale=guidance,
        height=height,
        width=width,
        generator=generator,
    ).images[0]
    
    # Ensure output directory exists
    output_file = Path(output_path)
    output_file.parent.mkdir(parents=True, exist_ok=True)
    
    image.save(output_file, format="PNG", quality=95)
    logger.info(f"Saved: {output_file}")
    
    return image


def generate_deck_batch(
    pipeline,
    output_dir: str,
    visuals: list[dict],
) -> list[Image.Image]:
    """Generate multiple deck visuals."""
    
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)
    
    images = []
    for i, visual in enumerate(visuals):
        logger.info(f"Generating visual {i+1}/{len(visuals)}: {visual['name']}")
        
        output_file = output_path / f"{visual['name']}.png"
        
        image = generate_visual(
            pipeline=pipeline,
            prompt=visual["prompt"],
            output_path=str(output_file),
            negative_prompt=visual.get("negative_prompt", ""),
            width=visual.get("width", 1024),
            height=visual.get("height", 1024),
            steps=visual.get("steps", 28),
            guidance=visual.get("guidance", 3.5),
            seed=visual.get("seed"),
        )
        
        images.append(image)
    
    return images


# Preset deck visuals based on Cannes deck slides
DECK_VISUALS = [
    {
        "name": "01_cover",
        "prompt": "the baker film style, title card THE BAKER, deep black background #121212, gold accent #B78A3C, elegant typography, grandeur with decay, cinematic, pitch deck title slide",
        "width": 1024,
        "height": 576,  # 16:9 for deck
    },
    {
        "name": "02_the_bargain",
        "prompt": "the baker film style, barakat estate interior, baroque catholic weight with phoenician memory, grand room showing decay and wealth, chiaroscuro lighting, dust motes in light shafts, cinematic, grandeur with decay",
    },
    {
        "name": "03_the_story",
        "prompt": "the baker film style, family dinner table, multiple generations, food abundance, underlying tension, chiaroscuro lighting, baroque setting, cinematic, grandeur with decay",
    },
    {
        "name": "04_fault_line",
        "prompt": "the baker film style, carved wooden family crest half-covered in shadow, bullet casing and communion wafer resting beside it on marble, symbolic, chiaroscuro lighting, cinematic, grandeur with decay",
    },
    {
        "name": "05_opening_wound",
        "prompt": "the baker film style, port of byblos at dawn, fishing caique eleftheria leaving, lebanon burning in background, blood and exile, crucifix sinking into sea, cinematic, grandeur with decay",
    },
    {
        "name": "06_fredric",
        "prompt": "the baker film style, fredric barakat portrait, aging drug lord patriarch, physically diminished, surrounded by photographs pills guns priests and ghosts, chiaroscuro lighting, baroque interior, cinematic, grandeur with decay",
    },
    {
        "name": "07_magda",
        "prompt": "the baker film style, magda barakat portrait, second wife matriarch, care as authority grief as power, black clothing, judging expression, chiaroscuro lighting, cinematic, grandeur with decay",
    },
    {
        "name": "08_billy",
        "prompt": "the baker film style, billy barakat portrait, reckless son, violence as identity, demanding empire, remote contempt, dim lighting, club background, cinematic, grandeur with decay",
    },
    {
        "name": "09_communion",
        "prompt": "the baker film style, maronite catholic church interior, holy communion ceremony, family in formal attire, candles and incense, religious iconography, chiaroscuro lighting, white dress communion girl, cinematic, grandeur with decay",
    },
    {
        "name": "10_lebanon",
        "prompt": "the baker film style, lebanese cemetery on slopes, two elaborate caskets descending, matriarch in black brocade silk, bishop blessing, israeli fighter jet in sky, cinematic, grandeur with decay",
    },
    {
        "name": "11_theme",
        "prompt": "the baker film style, bread and blood on family table, symbolic, grandeur with decay, chiaroscuro lighting, cinematic composition",
    },
    {
        "name": "12_audience",
        "prompt": "the baker film style, family gathering, diaspora viewers, recognition and tension, warm lighting, cinematic, grandeur with decay",
    },
    {
        "name": "13_closing",
        "prompt": "the baker film style, cemetery background, black and gold, THE END text space, cinematic, deck visual, grandeur with decay",
    },
]


def main():
    parser = argparse.ArgumentParser(description="Generate THE BAKER deck visuals")
    parser.add_argument("--prompt", type=str, help="Custom prompt for single image generation")
    parser.add_argument("--output", type=str, default="output.png", help="Output file path")
    parser.add_argument("--lora", type=str, help="Path to trained LoRA weights (.safetensors)")
    parser.add_argument("--base-model", type=str, default="black-forest-labs/FLUX.2-dev", help="Base model path")
    parser.add_argument("--batch", action="store_true", help="Generate all preset deck visuals")
    parser.add_argument("--output-dir", type=str, default="assets/decks/visuals", help="Output directory for batch generation")
    parser.add_argument("--width", type=int, default=1024, help="Image width")
    parser.add_argument("--height", type=int, default=1024, help="Image height")
    parser.add_argument("--steps", type=int, default=28, help="Inference steps")
    parser.add_argument("--guidance", type=float, default=3.5, help="Guidance scale")
    parser.add_argument("--seed", type=int, default=None, help="Random seed")
    args = parser.parse_args()
    
    # Check CUDA
    if not torch.cuda.is_available():
        logger.error("CUDA not available. GPU required.")
        return
    
    # Load pipeline
    pipeline = load_pipeline(args.base_model, args.lora)
    
    if args.batch:
        # Generate all preset visuals
        logger.info(f"Generating {len(DECK_VISUALS)} deck visuals...")
        generate_deck_batch(pipeline, args.output_dir, DECK_VISUALS)
        logger.info(f"Batch complete! Visuals saved to {args.output_dir}/")
    else:
        # Generate single image
        if not args.prompt:
            logger.error("--prompt required for single image generation")
            return
        
        generate_visual(
            pipeline=pipeline,
            prompt=args.prompt,
            output_path=args.output,
            width=args.width,
            height=args.height,
            steps=args.steps,
            guidance=args.guidance,
            seed=args.seed,
        )
        logger.info("Generation complete!")


if __name__ == "__main__":
    main()
