"""
FrankenClaw — vision_analyze tool

Reads an image from the host filesystem, encodes it, and sends it to
a vision-capable model via OpenRouter. Returns the model's description.

Keys come from the configured keys file. Model comes from FrankenClaw config.
"""

import base64
import io
import json
from pathlib import Path

import httpx
from PIL import Image

from config import load_config, get_key

OPENROUTER_API = "https://openrouter.ai/api/v1/chat/completions"


def _load_and_compress(image_path: str, max_bytes: int) -> tuple[str, str]:
    """Load image, compress if needed, return (base64_data, media_type)."""
    path = Path(image_path).expanduser()
    if not path.exists():
        raise FileNotFoundError(f"Image not found: {image_path}")

    # Detect media type from extension
    suffix = path.suffix.lower()
    media_types = {
        ".png": "image/png",
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".gif": "image/gif",
        ".webp": "image/webp",
        ".bmp": "image/bmp",
    }
    media_type = media_types.get(suffix, "image/png")

    raw = path.read_bytes()

    # If under limit, encode as-is
    if len(raw) <= max_bytes:
        return base64.b64encode(raw).decode(), media_type

    # Compress: convert to JPEG at decreasing quality
    img = Image.open(io.BytesIO(raw))
    if img.mode in ("RGBA", "P"):
        img = img.convert("RGB")

    for quality in (85, 70, 50, 30):
        buf = io.BytesIO()
        img.save(buf, format="JPEG", quality=quality)
        data = buf.getvalue()
        if len(data) <= max_bytes:
            return base64.b64encode(data).decode(), "image/jpeg"

    # Last resort: resize
    img.thumbnail((1024, 1024))
    buf = io.BytesIO()
    img.save(buf, format="JPEG", quality=50)
    return base64.b64encode(buf.getvalue()).decode(), "image/jpeg"


async def vision_analyze(image_path: str, prompt: str = "Describe this image in detail") -> str:
    """
    Analyze an image using a vision-capable model.

    Args:
        image_path: Absolute path to an image file on the host filesystem.
        prompt: What to ask the model about the image (default: describe it).

    Returns:
        JSON with the model's description and which model was used.
    """
    cfg = load_config()
    model = cfg["vision_model"]
    provider = cfg["vision_provider"]
    max_bytes = cfg["image_max_bytes"]
    api_key = get_key(provider)

    b64_data, media_type = _load_and_compress(image_path, max_bytes)

    payload = {
        "model": model,
        "messages": [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": prompt},
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": f"data:{media_type};base64,{b64_data}"
                        },
                    },
                ],
            }
        ],
        "max_tokens": 1024,
    }

    async with httpx.AsyncClient(timeout=30) as client:
        resp = await client.post(
            OPENROUTER_API,
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json",
            },
            json=payload,
        )
        resp.raise_for_status()
        data = resp.json()

    description = data["choices"][0]["message"]["content"]

    return json.dumps({
        "description": description,
        "model": model,
    }, indent=2)
