"""
Pollinations Image Provider – generates images from text prompts via Pollinations.ai API.

Supports multiple models: flux, zimage, gptimage, seedream, nanobanana, etc.

Env vars:
  POLLINATIONS_API_KEY - API key from enter.pollinations.ai (optional for limited use)
  POLLINATIONS_IMAGE_MODEL - Model to use (default: flux)

Docs: https://gen.pollinations.ai/docs
"""

from __future__ import annotations

import asyncio
import logging
import os
from pathlib import Path
from typing import Any
from urllib.parse import quote

import httpx

from providers.ports import ImageProvider

logger = logging.getLogger(__name__)

POLLINATIONS_BASE_URL = "https://gen.pollinations.ai"

# Available image models (from OpenAPI spec)
IMAGE_MODELS = [
    "flux",  # High quality, recommended
    "zimage",  # Default in API, fast generation
    "kontext",  # Context-aware generation
    "nanobanana",  # Fast generation
    "nanobanana-pro",  # Fast generation (pro)
    "seedream",  # Dreamlike style
    "seedream-pro",  # Dreamlike style (pro)
    "gptimage",  # GPT-4 image generation
    "gptimage-large",  # GPT-4 large image generation
    "klein",  # Klein model
    "klein-large",  # Klein large model
]


class PollinationsImageProvider(ImageProvider):
    """Wraps the Pollinations.ai API for image generation."""

    name = "pollinations"

    def __init__(self, api_key: str | None = None):
        """Initialize the Pollinations image provider.

        Args:
            api_key: Optional API key. If not provided, uses POLLINATIONS_API_KEY env var.
                    Can work without key for limited usage.
        """
        self.api_key = api_key or os.getenv("POLLINATIONS_API_KEY", "")
        self.base_url = POLLINATIONS_BASE_URL
        self.model = os.getenv("POLLINATIONS_IMAGE_MODEL", "flux")
        self.width = int(os.getenv("POLLINATIONS_IMAGE_WIDTH", "1024"))
        self.height = int(os.getenv("POLLINATIONS_IMAGE_HEIGHT", "1024"))

        if self.model not in IMAGE_MODELS:
            logger.warning(
                "Unknown image model '%s', using 'flux'. Available: %s",
                self.model,
                IMAGE_MODELS,
            )
            self.model = "flux"

    def _generate_sync(
        self,
        prompt: str,
        output_path: str | Path,
        width: int | None = None,
        height: int | None = None,
        model: str | None = None,
        seed: int = -1,
        enhance: bool = False,
        negative_prompt: str = "worst quality, blurry",
        safe: bool = False,
        quality: str = "medium",
        transparent: bool = False,
    ) -> Path:
        """Generate an image from prompt and save to output_path.

        Args:
            prompt: Text description of the image to generate
            output_path: Where to save the generated image
            width: Image width in pixels (default: 1024)
            height: Image height in pixels (default: 1024)
            model: AI model to use (default: from env or 'flux')
            seed: Random seed for reproducibility (-1 for random)
            enhance: Let AI improve the prompt
            negative_prompt: What to avoid in the image
            safe: Enable safety content filters
            quality: Image quality level (gptimage only): low, medium, high, hd
            transparent: Generate with transparent background (gptimage only)

        Returns:
            Path to the saved image file
        """
        output_path = Path(output_path)
        output_path.parent.mkdir(parents=True, exist_ok=True)

        # Use provided values or defaults
        width = width or self.width
        height = height or self.height
        model = model or self.model

        # URL encode the prompt
        encoded_prompt = quote(prompt, safe="")

        # Build URL with query parameters
        url = f"{self.base_url}/image/{encoded_prompt}"

        params = {
            "model": model,
            "width": width,
            "height": height,
            "seed": seed,
            "enhance": str(enhance).lower(),
            "negative_prompt": negative_prompt,
            "safe": str(safe).lower(),
        }

        # Add model-specific params
        if model in ("gptimage", "gptimage-large"):
            params["quality"] = quality
            params["transparent"] = str(transparent).lower()

        # Add API key to query params (alternative auth method)
        if self.api_key:
            params["key"] = self.api_key

        # Build headers
        headers = {"Accept": "image/*"}
        if self.api_key:
            headers["Authorization"] = f"Bearer {self.api_key}"

        logger.info(
            "Generating image via Pollinations: model=%s size=%dx%d → %s",
            model,
            width,
            height,
            output_path,
        )
        logger.debug("Prompt: %s", prompt[:100])

        # Make request with long timeout (image generation can take time)
        with httpx.Client(timeout=180) as client:
            response = client.get(url, params=params, headers=headers)
            response.raise_for_status()

            # Save image
            output_path.write_bytes(response.content)

        logger.info("Image saved: %s (%d bytes)", output_path, len(response.content))
        return output_path

    async def generate(
        self,
        prompt: str,
        output_path: Path,
        **kwargs: Any,
    ) -> Path:
        """Generate an image asynchronously."""
        return await asyncio.to_thread(
            self._generate_sync, prompt, output_path, **kwargs
        )

    @staticmethod
    def list_models() -> list[str]:
        """Return list of available image models."""
        return IMAGE_MODELS.copy()
