"""GPT Image 2 blog image generation via OpenAI Images API."""

import base64
import logging
from typing import Any

import requests
from django.conf import settings

logger = logging.getLogger(__name__)


class OpenAIImageClient:
    """OpenAI Images API client for blog header and inline images."""

    IMAGES_URL = "https://api.openai.com/v1/images/generations"
    DEFAULT_MODEL = "gpt-image-2"
    DEFAULT_SIZE = "1536x1024"
    DEFAULT_QUALITY = "high"
    REQUEST_TIMEOUT = 300

    NO_TEXT_SUFFIX = (
        "no text, no labels, no words, no letters, no numbers, no watermarks, "
        "no captions, no logos, no signs, no writing, no typography"
    )

    @classmethod
    def _api_key(cls) -> str:
        key = (getattr(settings, "OPENAI_API_KEY", None) or "").strip().strip('"').strip("'")
        if not key:
            raise RuntimeError("OPENAI_API_KEY not configured")
        return key

    @classmethod
    def _model(cls) -> str:
        return (getattr(settings, "OPENAI_IMAGE_MODEL", None) or cls.DEFAULT_MODEL).strip() or cls.DEFAULT_MODEL

    @classmethod
    def _headers(cls) -> dict[str, str]:
        return {
            "Authorization": f"Bearer {cls._api_key()}",
            "Content-Type": "application/json",
        }

    @classmethod
    def _finalize_prompt(cls, prompt: str) -> str:
        return f"{prompt.strip()}. {cls.NO_TEXT_SUFFIX}"

    @classmethod
    def _image_bytes_from_response(cls, item: dict[str, Any]) -> bytes:
        if b64 := item.get("b64_json"):
            return base64.b64decode(b64)
        if url := item.get("url"):
            resp = requests.get(url, timeout=120)
            resp.raise_for_status()
            return resp.content
        raise RuntimeError("OpenAI image API returned no url or b64_json")

    @classmethod
    def _api_error_message(cls, resp: requests.Response) -> str:
        try:
            err = resp.json().get("error") or {}
            return err.get("message") or resp.text[:500]
        except Exception:
            return resp.text[:500]

    @classmethod
    def generate(
        cls,
        prompt: str,
        *,
        size: str | None = None,
        quality: str | None = None,
    ) -> dict[str, Any]:
        final_prompt = cls._finalize_prompt(prompt)
        resp = requests.post(
            cls.IMAGES_URL,
            headers=cls._headers(),
            json={
                "model": cls._model(),
                "prompt": final_prompt,
                "size": size or cls.DEFAULT_SIZE,
                "quality": quality or cls.DEFAULT_QUALITY,
                "n": 1,
            },
            timeout=cls.REQUEST_TIMEOUT,
        )
        if resp.status_code >= 400:
            msg = cls._api_error_message(resp)
            logger.error("OpenAI image API error %s: %s", resp.status_code, msg)
            raise RuntimeError(f"OpenAI image API error ({resp.status_code}): {msg}")

        data: list[dict[str, Any]] = resp.json().get("data") or []
        if not data:
            raise RuntimeError("OpenAI image API returned empty data")

        return {
            "image_bytes": cls._image_bytes_from_response(data[0]),
            "prompt_used": final_prompt,
        }

    @classmethod
    def generate_header(cls, topic: str, niche: str = "") -> dict[str, Any]:
        niche_clause = f"Related to {niche}. " if niche else ""
        prompt = (
            f"Professional blog header image about {topic}. "
            f"{niche_clause}"
            "Clean modern aesthetic, wide banner."
        )
        return cls.generate(prompt)

    @classmethod
    def generate_inline(cls, description: str) -> dict[str, Any]:
        return cls.generate(f"{description}. Professional high quality illustration.")
