#!/usr/bin/env python3
"""
Jimeng Image Generator Script
Generates images using the local Jimeng API and downloads them to the /pic folder.
"""

import os
import sys
import argparse
import requests
from pathlib import Path
from datetime import datetime
from io import BytesIO

try:
    from PIL import Image
    PIL_AVAILABLE = True
except ImportError:
    PIL_AVAILABLE = False
    print("⚠️  Warning: Pillow not installed. WebP images will be saved as-is.")
    print("   Install with: pip install Pillow")


def generate_text_to_image(
    prompt: str,
    session_id: str,
    model: str = "jimeng-4.0",
    ratio: str = "1:1",
    resolution: str = "2k",
    intelligent_ratio: bool = False,
    negative_prompt: str = None,
    sample_strength: float = None,
    api_url: str = "http://localhost:5100",
    output_dir: str = None
):
    """
    Generate images from text using the Jimeng API (文生图).

    Args:
        prompt: The text prompt for image generation
        session_id: Jimeng session ID (with region prefix if needed)
        model: Model to use (jimeng-4.0, jimeng-3.1, etc.)
        ratio: Aspect ratio (1:1, 16:9, etc.)
        resolution: Resolution level (1k, 2k, 4k)
        intelligent_ratio: Enable automatic ratio detection
        negative_prompt: Negative prompt (elements to avoid)
        sample_strength: Sampling strength (0.0-1.0)
        api_url: Jimeng API base URL
        output_dir: Output directory for downloaded images

    Returns:
        List of downloaded image file paths
    """
    endpoint = f"{api_url}/v1/images/generations"

    # Prepare request payload
    payload = {
        "model": model,
        "prompt": prompt,
        "ratio": ratio,
        "resolution": resolution,
        "intelligent_ratio": intelligent_ratio
    }

    if negative_prompt:
        payload["negative_prompt"] = negative_prompt

    if sample_strength is not None:
        payload["sample_strength"] = sample_strength

    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {session_id}"
    }

    print(f"🎨 Generating image(s) with prompt: {prompt[:60]}...")
    print(f"📐 Model: {model}, Ratio: {ratio}, Resolution: {resolution}")

    # Call the API
    try:
        response = requests.post(endpoint, json=payload, headers=headers, timeout=300)
        response.raise_for_status()
        api_response = response.json()
    except requests.exceptions.RequestException as e:
        print(f"❌ Error calling API: {e}")
        if hasattr(e, 'response') and e.response is not None:
            print(f"   Response: {e.response.text}")
        sys.exit(1)

    # Download images
    return download_images(api_response, output_dir, "text")


def generate_image_to_image(
    prompt: str,
    session_id: str,
    images: list,
    model: str = "jimeng-4.0",
    ratio: str = "1:1",
    resolution: str = "2k",
    intelligent_ratio: bool = False,
    negative_prompt: str = None,
    sample_strength: float = None,
    api_url: str = "http://localhost:5100",
    output_dir: str = None
):
    """
    Generate images from input images using the Jimeng API (图生图).

    Args:
        prompt: The text prompt for image generation
        session_id: Jimeng session ID
        images: List of image paths or URLs (1-10 images)
        model: Model to use
        ratio: Aspect ratio
        resolution: Resolution level
        intelligent_ratio: Enable automatic ratio detection
        negative_prompt: Negative prompt
        sample_strength: Sampling strength
        api_url: Jimeng API base URL
        output_dir: Output directory for downloaded images

    Returns:
        List of downloaded image file paths
    """
    endpoint = f"{api_url}/v1/images/compositions"

    headers = {
        "Authorization": f"Bearer {session_id}"
    }

    # Determine if we need multipart/form-data (local files) or JSON (URLs)
    has_local_files = any(os.path.exists(img) for img in images)

    print(f"🎨 Generating image composition with prompt: {prompt[:60]}...")
    print(f"📐 Input images: {len(images)}, Model: {model}")

    try:
        if has_local_files:
            # Use multipart/form-data for file uploads
            files = []
            data = {
                "prompt": prompt,
                "model": model,
                "ratio": ratio,
                "resolution": resolution
            }

            if intelligent_ratio:
                data["intelligent_ratio"] = "true"

            if negative_prompt:
                data["negative_prompt"] = negative_prompt

            if sample_strength is not None:
                data["sample_strength"] = str(sample_strength)

            # Add image files
            for img_path in images:
                if os.path.exists(img_path):
                    files.append(('images', open(img_path, 'rb')))
                else:
                    # Assume it's a URL
                    if 'images' not in data:
                        data['images'] = []
                    data['images'].append(img_path)

            response = requests.post(endpoint, data=data, files=files, headers=headers, timeout=300)

            # Close file handles
            for _, file_obj in files:
                file_obj.close()
        else:
            # Use JSON for URL-based images
            headers["Content-Type"] = "application/json"
            payload = {
                "model": model,
                "prompt": prompt,
                "images": images,
                "ratio": ratio,
                "resolution": resolution,
                "intelligent_ratio": intelligent_ratio
            }

            if negative_prompt:
                payload["negative_prompt"] = negative_prompt

            if sample_strength is not None:
                payload["sample_strength"] = sample_strength

            response = requests.post(endpoint, json=payload, headers=headers, timeout=300)

        response.raise_for_status()
        api_response = response.json()

    except requests.exceptions.RequestException as e:
        print(f"❌ Error calling API: {e}")
        if hasattr(e, 'response') and e.response is not None:
            print(f"   Response: {e.response.text}")
        sys.exit(1)

    # Download images
    return download_images(api_response, output_dir, "composition")


def download_images(api_response: dict, output_dir: str, mode: str):
    """
    Download images from API response URLs.

    Args:
        api_response: JSON response from Jimeng API
        output_dir: Output directory path
        mode: Generation mode ("text" or "composition")

    Returns:
        List of downloaded file paths
    """
    # Determine output directory
    if output_dir is None:
        # Find project root
        current_dir = Path.cwd()
        project_root = current_dir

        # Look for project markers
        while project_root.parent != project_root:
            if any((project_root / marker).exists() for marker in
                   ['.git', '.claude', 'package.json', 'pyproject.toml', 'requirements.txt']):
                break
            project_root = project_root.parent

        output_dir = project_root / "pic"
    else:
        output_dir = Path(output_dir)

    # Create output directory
    output_dir.mkdir(parents=True, exist_ok=True)
    print(f"📁 Output directory: {output_dir}")

    # Download images
    downloaded_files = []
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

    image_data_list = api_response.get("data", [])

    if not image_data_list:
        print("⚠️  No images in API response")
        return downloaded_files

    for idx, image_data in enumerate(image_data_list):
        image_url = image_data.get("url")

        if not image_url:
            print(f"⚠️  No URL for image {idx + 1}")
            continue

        print(f"🔗 Image {idx + 1}/{len(image_data_list)}: {image_url[:80]}...")

        # Download image
        try:
            img_response = requests.get(image_url, timeout=60)
            img_response.raise_for_status()

            # Detect if image is WebP format
            is_webp = ("format=.webp" in image_url or
                      image_url.endswith(".webp") or
                      img_response.content[:4] == b'RIFF')  # WebP magic number

            # Generate filename (always save as PNG)
            filename = f"jimeng_{timestamp}_{idx + 1}.png"
            file_path = output_dir / filename

            # Convert WebP to PNG if needed
            if is_webp and PIL_AVAILABLE:
                try:
                    # Load WebP image and convert to PNG
                    img = Image.open(BytesIO(img_response.content))

                    # Convert RGBA to RGB if needed (PNG supports both)
                    if img.mode in ('RGBA', 'LA', 'P'):
                        # Keep transparency
                        img.save(file_path, 'PNG', optimize=True)
                    else:
                        img.save(file_path, 'PNG', optimize=True)

                    print(f"✅ Downloaded and converted (WebP→PNG): {file_path}")
                except Exception as e:
                    print(f"⚠️  WebP conversion failed, saving original: {e}")
                    # Fallback: save as-is
                    with open(file_path.with_suffix('.webp'), 'wb') as f:
                        f.write(img_response.content)
                    file_path = file_path.with_suffix('.webp')
            else:
                # Save directly (PNG, JPG, or WebP without PIL)
                if is_webp and not PIL_AVAILABLE:
                    # No Pillow, save as WebP
                    file_path = file_path.with_suffix('.webp')
                    print(f"⚠️  Saving as WebP (Pillow not available)")

                with open(file_path, 'wb') as f:
                    f.write(img_response.content)

                print(f"✅ Downloaded: {file_path}")

            downloaded_files.append(str(file_path))

        except requests.exceptions.RequestException as e:
            print(f"❌ Error downloading image {idx + 1}: {e}")

    # Print summary
    print(f"\n📊 Summary:")
    print(f"   Created at: {api_response.get('created', 'N/A')}")
    print(f"   Downloaded: {len(downloaded_files)}/{len(image_data_list)} images")

    if mode == "composition" and "input_images" in api_response:
        print(f"   Input images: {api_response['input_images']}")
        print(f"   Composition type: {api_response.get('composition_type', 'N/A')}")

    return downloaded_files


def main():
    parser = argparse.ArgumentParser(
        description="Generate images using local Jimeng API",
        formatter_class=argparse.RawDescriptionHelpFormatter
    )

    subparsers = parser.add_subparsers(dest="mode", help="Generation mode")

    # Text-to-Image subcommand
    text_parser = subparsers.add_parser("text", help="Text-to-image generation (文生图)")
    text_parser.add_argument("prompt", type=str, help="Text prompt for image generation")

    # Image-to-Image subcommand
    image_parser = subparsers.add_parser("image", help="Image-to-image generation (图生图)")
    image_parser.add_argument("prompt", type=str, help="Text prompt for image transformation")
    image_parser.add_argument(
        "--images",
        nargs="+",
        required=True,
        help="Input image paths or URLs (1-10 images)"
    )

    # Common arguments for both modes
    for subparser in [text_parser, image_parser]:
        subparser.add_argument(
            "--session-id",
            type=str,
            required=True,
            help="Jimeng session ID (with region prefix if needed: us-/hk-/jp-/sg-)"
        )
        subparser.add_argument(
            "--model",
            type=str,
            default="jimeng-4.5",
            choices=["jimeng-5.0", "jimeng-4.6", "jimeng-4.5", "jimeng-4.1", "jimeng-4.0", "jimeng-3.1", "jimeng-3.0", "nanobanana"],
            help="Model to use (default: jimeng-4.5)"
        )
        subparser.add_argument(
            "--ratio",
            type=str,
            default="1:1",
            choices=["1:1", "4:3", "3:4", "16:9", "9:16", "3:2", "2:3", "21:9"],
            help="Aspect ratio (default: 1:1)"
        )
        subparser.add_argument(
            "--resolution",
            type=str,
            default="2k",
            choices=["1k", "2k", "4k"],
            help="Resolution level (default: 2k)"
        )
        subparser.add_argument(
            "--intelligent-ratio",
            action="store_true",
            help="Enable automatic ratio detection based on prompt"
        )
        subparser.add_argument(
            "--negative-prompt",
            type=str,
            help="Negative prompt (elements to avoid)"
        )
        subparser.add_argument(
            "--sample-strength",
            type=float,
            help="Sampling strength (0.0-1.0)"
        )
        subparser.add_argument(
            "--api-url",
            type=str,
            default="http://localhost:5100",
            help="Jimeng API base URL (default: http://localhost:5100)"
        )
        subparser.add_argument(
            "--output-dir",
            type=str,
            help="Output directory for images (defaults to project_root/pic)"
        )

    args = parser.parse_args()

    # Check if mode is specified
    if not args.mode:
        parser.print_help()
        sys.exit(1)

    # Validate sample_strength
    if args.sample_strength is not None:
        if args.sample_strength < 0.0 or args.sample_strength > 1.0:
            print("❌ Error: sample_strength must be between 0.0 and 1.0")
            sys.exit(1)

    # Generate images
    try:
        if args.mode == "text":
            downloaded_files = generate_text_to_image(
                prompt=args.prompt,
                session_id=args.session_id,
                model=args.model,
                ratio=args.ratio,
                resolution=args.resolution,
                intelligent_ratio=args.intelligent_ratio,
                negative_prompt=args.negative_prompt,
                sample_strength=args.sample_strength,
                api_url=args.api_url,
                output_dir=args.output_dir
            )
        else:  # image mode
            # Validate image count
            if len(args.images) < 1 or len(args.images) > 10:
                print("❌ Error: Number of images must be between 1 and 10")
                sys.exit(1)

            downloaded_files = generate_image_to_image(
                prompt=args.prompt,
                session_id=args.session_id,
                images=args.images,
                model=args.model,
                ratio=args.ratio,
                resolution=args.resolution,
                intelligent_ratio=args.intelligent_ratio,
                negative_prompt=args.negative_prompt,
                sample_strength=args.sample_strength,
                api_url=args.api_url,
                output_dir=args.output_dir
            )

        print(f"\n✨ Successfully generated and downloaded {len(downloaded_files)} image(s)!")

    except KeyboardInterrupt:
        print("\n\n⚠️  Generation cancelled by user")
        sys.exit(1)


if __name__ == "__main__":
    main()
