"""
Laterless API Client

Wraps httpx AsyncClient with 6 API methods.
Unified error handling: network/HTTP errors are converted to ToolError
so the MCP framework can return proper error responses to the client.
"""

import httpx
from mcp.server.fastmcp.exceptions import ToolError


class LaterlessClient:
    """Async client for the Laterless API."""

    def __init__(self, http_client: httpx.AsyncClient | None = None):
        """
        Initialize client.

        http_client: Externally injected httpx.AsyncClient (lifecycle managed by lifespan).
                     Falls back to creating its own client if not provided,
                     but caller must call close() in that case.
        """
        self._client = http_client
        self._owns_client = http_client is None
        if self._owns_client:
            # Backward compat: create own client when none is injected
            from .config import get_api_key, get_api_url
            self._client = httpx.AsyncClient(
                base_url=get_api_url(),
                headers={"Authorization": f"Bearer {get_api_key()}"},
                timeout=30.0,
            )

    async def _request(self, method: str, path: str, **kwargs) -> dict:
        """
        Unified HTTP request handler.

        401 -> clear message about invalid API key
        Other HTTP errors -> include status code and message
        Network errors -> wrap as ToolError
        """
        try:
            response = await self._client.request(method, path, **kwargs)
        except httpx.HTTPError as e:
            # Timeout, DNS failure, connection refused, etc.
            raise ToolError(f"Network error: {e}") from e

        if response.status_code == 401:
            raise ToolError("API key is invalid or revoked. Please check your LATERLESS_API_KEY.")

        if response.status_code >= 400:
            detail = response.text
            try:
                detail = response.json().get("detail", response.text)
            except Exception:
                pass
            raise ToolError(f"API error ({response.status_code}): {detail}")

        return response.json()

    async def search_bookmarks(self, query: str, limit: int = 10) -> dict:
        """Semantic search bookmarks. Returns { bookmarks: [...], query: "..." }"""
        return await self._request("GET", "/api/bookmarks/search", params={
            "q": query,
            "limit": limit,
        })

    async def list_bookmarks(self, limit: int = 20, offset: int = 0) -> dict:
        """List recent bookmarks. Returns { bookmarks: [...], total, offset, limit }"""
        return await self._request("GET", "/api/bookmarks", params={
            "limit": limit,
            "offset": offset,
        })

    async def get_bookmark(self, bookmark_id: str) -> dict:
        """Get full bookmark details. Returns BookmarkDetailResponse (with content, key_concepts, etc.)"""
        return await self._request("GET", f"/api/bookmarks/{bookmark_id}")

    async def add_bookmark(self, url: str, title: str | None = None) -> dict:
        """Add a bookmark by URL. Returns { id, url, title, source, created_at }"""
        body: dict = {"url": url}
        if title:
            body["title"] = title
        return await self._request("POST", "/api/bookmarks", json=body)

    async def add_brain_dump(self, content: str) -> dict:
        """Save a text brain dump. Returns { id, content, source, created_at, has_images }"""
        return await self._request("POST", "/api/bookmarks/brain-dump", json={
            "content": content,
        })

    async def get_profile(self) -> dict:
        """Get user profile (stats, connection status). Returns UserProfileResponse"""
        return await self._request("GET", "/api/user/profile")

    async def close(self):
        """Close HTTP connection (only needed when client owns the httpx instance)."""
        if self._owns_client:
            await self._client.aclose()
