"""AI-based frame selection using Anthropic Claude Vision."""

import base64
import json
import sys
import time
from typing import Optional, Tuple

DEFAULT_CLAUDE_MODEL = "claude-opus-4-5"
MAX_RETRIES = 2
RETRY_BASE_DELAY = 2  # seconds
MAX_DESCRIPTION_LENGTH = 1000


def _encode_image(image_path: str) -> str:
    """Return base64-encoded content of an image file."""
    with open(image_path, "rb") as f:
        return base64.standard_b64encode(f.read()).decode("utf-8")


def select_frame_with_ai(
    mosaic_path: str,
    api_key: str,
    model: str = DEFAULT_CLAUDE_MODEL,
    description: Optional[str] = None,
) -> Tuple[int, str]:
    """
    Ask Claude Vision to select the best frame from a mosaic image.

    Parameters
    ----------
    mosaic_path:
        Path to the mosaic JPEG image.
    api_key:
        Anthropic API key.
    model:
        Claude model name.
    description:
        Optional description of the video content for context (max 1000 chars).

    Returns
    -------
    (frame_index, reasoning)
        ``frame_index`` is an integer 0–19.
        ``reasoning`` is the AI explanation.

    Raises
    ------
    RuntimeError
        If the AI call fails after all retries or returns an invalid response.
    """
    try:
        import anthropic
    except ImportError:
        raise RuntimeError(
            "The 'anthropic' package is required for AI selection. "
            "Install it with: pip install anthropic"
        )

    if description:
        description = description[:MAX_DESCRIPTION_LENGTH]

    image_data = _encode_image(mosaic_path)

    context_block = ""
    if description:
        context_block = (
            f"\n\nVideo description provided by the user:\n{description}"
        )

    prompt = (
        "You are shown a mosaic of 20 video frames arranged in a 4-column × 5-row grid. "
        "Each frame is labelled 'BILD 0' through 'BILD 19' (top-left to bottom-right). "
        "Select the single best frame to use as a video thumbnail poster image. "
        "Prefer frames that are sharp, well-lit, visually interesting, and representative "
        "of the video content. Avoid frames with motion blur, closed eyes, or transitional "
        f"content.{context_block}\n\n"
        "Respond ONLY with a valid JSON object on a single line, with no additional text:\n"
        '{"image_number": <integer 0-19>, "reasoning": "<brief explanation>"}'
    )

    client = anthropic.Anthropic(api_key=api_key)

    last_error: Optional[Exception] = None
    for attempt in range(MAX_RETRIES):
        try:
            message = client.messages.create(
                model=model,
                max_tokens=256,
                messages=[
                    {
                        "role": "user",
                        "content": [
                            {
                                "type": "image",
                                "source": {
                                    "type": "base64",
                                    "media_type": "image/jpeg",
                                    "data": image_data,
                                },
                            },
                            {
                                "type": "text",
                                "text": prompt,
                            },
                        ],
                    }
                ],
            )

            raw = message.content[0].text.strip()
            # Strip markdown code fences if present
            if raw.startswith("```"):
                raw = raw.split("```")[1]
                if raw.startswith("json"):
                    raw = raw[4:]
                raw = raw.strip()

            data = json.loads(raw)
            frame_index = int(data["image_number"])
            reasoning = str(data["reasoning"])

            if not (0 <= frame_index <= 19):
                raise ValueError(
                    f"frame_index {frame_index} is out of range 0–19."
                )

            return frame_index, reasoning

        except Exception as exc:  # noqa: BLE001
            last_error = exc
            if attempt < MAX_RETRIES - 1:
                delay = RETRY_BASE_DELAY * (2 ** attempt)
                print(
                    f"   ⚠️  AI attempt {attempt + 1} failed: {exc}. "
                    f"Retrying in {delay}s…",
                    file=sys.stderr,
                )
                time.sleep(delay)

    raise RuntimeError(
        f"AI frame selection failed after {MAX_RETRIES} attempts: {last_error}"
    )
