"""Image view tool — load an image from a file path or URL for the LLM to analyse.

The image is returned as base64 and injected into the conversation so the LLM
can actually see it (not just read a text description of it).
"""

import base64
import mimetypes
from pathlib import Path

import httpx

from .base import Tool, ToolResult

_TIMEOUT = 30
_SUPPORTED = {".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"}


class ImageViewTool(Tool):
    name = "image_view"
    description = (
        "Load an image from a local file path or HTTP/HTTPS URL so you can see and analyse it. "
        "Call this whenever the user mentions an image file or URL, or when you need to "
        "inspect visual content. The image becomes visible to you in the next message."
    )
    parameters = {
        "type": "object",
        "properties": {
            "source": {
                "type": "string",
                "description": "Absolute file path (e.g. /home/user/photo.jpg) or HTTP/HTTPS URL",
            },
        },
        "required": ["source"],
    }

    async def execute(self, params: dict) -> ToolResult:
        source = params["source"].strip()
        try:
            if source.startswith(("http://", "https://")):
                raw, mime = await self._fetch_url(source)
            else:
                raw, mime = self._read_file(source)

            b64 = base64.b64encode(raw).decode()
            size_kb = len(raw) // 1024
            return ToolResult(
                success=True,
                output=f"Image loaded ({size_kb} KB, {mime}). It will appear in the next turn.",
                metadata={"base64": b64, "mime": mime, "is_image": True},
            )
        except Exception as e:
            return ToolResult(success=False, output=f"Failed to load image: {e}", error=str(e))

    async def _fetch_url(self, url: str) -> tuple[bytes, str]:
        async with httpx.AsyncClient(timeout=_TIMEOUT, follow_redirects=True) as client:
            r = await client.get(url)
            r.raise_for_status()
        mime = r.headers.get("content-type", "image/jpeg").split(";")[0].strip()
        return r.content, mime

    def _read_file(self, path_str: str) -> tuple[bytes, str]:
        path = Path(path_str).expanduser().resolve()
        if not path.exists():
            raise FileNotFoundError(f"File not found: {path}")
        if path.suffix.lower() not in _SUPPORTED:
            raise ValueError(f"Unsupported image format: {path.suffix}")
        mime = mimetypes.guess_type(str(path))[0] or "image/jpeg"
        return path.read_bytes(), mime
