"""Thin async httpx wrapper for the DialogBrain REST API."""
from __future__ import annotations

import httpx


class _Resource:
    def __init__(self, http: httpx.AsyncClient) -> None:
        self._http = http

    async def _get(self, path: str, **params) -> dict | list:
        resp = await self._http.get(path, params={k: v for k, v in params.items() if v is not None})
        resp.raise_for_status()
        return resp.json()

    async def _post(self, path: str, body: dict) -> dict | list:
        resp = await self._http.post(path, json=body)
        resp.raise_for_status()
        return resp.json()

    async def _patch(self, path: str, body: dict) -> dict | list:
        resp = await self._http.patch(path, json=body)
        resp.raise_for_status()
        return resp.json()


class _ConversationsResource(_Resource):
    async def list(self, limit: int = 50, offset: int = 0) -> list:
        result = await self._get("/api/v1/conversations", limit=limit, offset=offset)
        return result["items"] if isinstance(result, dict) else result  # type: ignore[index]

    async def get(self, conversation_id: str) -> dict:
        return await self._get(f"/api/v1/conversations/{conversation_id}")  # type: ignore[return-value]

    async def get_messages(self, conversation_id: str, limit: int = 50) -> list:
        return await self._get(f"/api/v1/conversations/{conversation_id}/messages", limit=limit)  # type: ignore[return-value]


class _MessagesResource(_Resource):
    async def send(self, thread_id: str, message_text: str) -> dict:
        return await self._post("/api/v1/messages/send", {"thread_id": thread_id, "message_text": message_text})  # type: ignore[return-value]


class _ContactsResource(_Resource):
    async def list(self) -> list:
        result = await self._get("/api/v1/contacts")
        return result["items"] if isinstance(result, dict) else result  # type: ignore[index]

    async def get(self, contact_id: str) -> dict:
        return await self._get(f"/api/v1/contacts/{contact_id}")  # type: ignore[return-value]

    async def update(self, contact_id: str, **fields) -> dict:
        return await self._patch(f"/api/v1/contacts/{contact_id}", fields)  # type: ignore[return-value]

    async def search(self, query: str, channel: str | None = None) -> list:
        body: dict = {"query": query}
        if channel:
            body["channel"] = channel
        return await self._post("/api/v1/contacts/discover", body)  # type: ignore[return-value]


class _SearchResource(_Resource):
    async def rag(self, query: str, limit: int = 5) -> list:
        return await self._post("/api/v1/search/rag", {"query": query, "limit": limit})  # type: ignore[return-value]


class DialogBrainClient:
    """
    Async client for the DialogBrain REST API.

    Usage:
        async with DialogBrainClient(api_key="db_live_...") as client:
            conversations = await client.conversations.list()
            await client.messages.send(thread_id="...", message_text="Hello!")
    """

    def __init__(self, api_key: str, base_url: str = "https://api.dialogbrain.com") -> None:
        self._http = httpx.AsyncClient(
            base_url=base_url,
            headers={"X-API-Key": api_key},
            timeout=30.0,
        )
        self.conversations = _ConversationsResource(self._http)
        self.messages = _MessagesResource(self._http)
        self.contacts = _ContactsResource(self._http)
        self.search = _SearchResource(self._http)

    async def handoff(self, thread_id: str, reason: str | None = None) -> dict:
        """Request human takeover for a thread."""
        body: dict = {"thread_id": thread_id}
        if reason:
            body["reason"] = reason
        resp = await self._http.post("/api/v1/handoff", json=body)
        resp.raise_for_status()
        return resp.json()

    async def close(self) -> None:
        await self._http.aclose()

    async def __aenter__(self) -> "DialogBrainClient":
        return self

    async def __aexit__(self, *_) -> None:
        await self.close()
