"""
Clew Context Engine: Graph + Vector hybrid search.

Queries the Clew API for context, which combines vector similarity
with graph traversal (IMPORTS, CALLS, DEFINES relationships) to
provide focused, de-duplicated context.
"""

from __future__ import annotations

import logging

import httpx

from .base import ContextResult, estimate_tokens

logger = logging.getLogger("clew.bench.engines.clew")


class ClewContextEngine:
    """Clew Engine context retrieval via the Clew API."""

    def __init__(self, api_url: str, repo: str | None = None, limit: int = 10):
        self.api_url = api_url.rstrip("/")
        self.repo = repo
        self.limit = limit
        self._client = httpx.AsyncClient(timeout=30.0)

    async def query(self, instruction: str) -> ContextResult:
        """
        Query Clew's hybrid search endpoint.

        Calls POST /v1/search with the instruction, then formats
        the returned code chunks into a context string.
        """
        payload: dict = {"query": instruction, "limit": self.limit, "rerank": True}
        if self.repo:
            payload["repo"] = self.repo

        try:
            response = await self._client.post(f"{self.api_url}/v1/search/", json=payload)
            response.raise_for_status()
            results = response.json()
        except httpx.HTTPError as e:
            logger.error("Clew API request failed: %s", e)
            return ContextResult(context="", token_count=0, sources=[])

        # Format results into a context block
        sections = []
        sources = []
        for r in results:
            path = r.get("metadata", {}).get("path", r.get("id", "unknown"))
            content = r.get("content", "")
            sources.append(path)
            sections.append(f"### {path}\n```\n{content}\n```")

        context = "\n\n".join(sections)
        token_count = estimate_tokens(context)

        logger.info("Clew returned %d results, ~%d tokens", len(results), token_count)
        return ContextResult(context=context, token_count=token_count, sources=sources)

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