# ClawTex — Governed Agent with Genetic Memory
# Built by DeVere Cooley / AN2B LLC · an2b.com
# BB4C — Breath Before Code

"""
Web search tool — searches the web using Brave Search API or DuckDuckGo fallback.

action_type: web.search
"""

from __future__ import annotations

import logging
import os
from typing import Any

import httpx

from .registry import registry

logger = logging.getLogger(__name__)


@registry.register(
    name="web_search",
    action_type="web.search",
    description="Search the web and return a list of relevant results.",
    parameters={
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "The search query.",
            },
            "count": {
                "type": "integer",
                "description": "Number of results to return (default 5).",
                "default": 5,
            },
        },
        "required": ["query"],
    },
)
async def web_search(query: str, count: int = 5, **_: Any) -> dict[str, Any]:
    """Search the web. Uses Brave Search API if BRAVE_API_KEY is set, else DuckDuckGo."""

    brave_key = os.environ.get("BRAVE_API_KEY")

    if brave_key:
        return await _brave_search(query, count, brave_key)
    else:
        return await _ddg_search(query, count)


async def _brave_search(
    query: str, count: int, api_key: str
) -> dict[str, Any]:
    url = "https://api.search.brave.com/res/v1/web/search"
    headers = {
        "Accept": "application/json",
        "X-Subscription-Token": api_key,
    }
    params = {"q": query, "count": min(count, 20)}
    async with httpx.AsyncClient(timeout=15.0) as client:
        resp = await client.get(url, headers=headers, params=params)
        resp.raise_for_status()
        data = resp.json()

    results = []
    for item in data.get("web", {}).get("results", [])[:count]:
        results.append(
            {
                "title": item.get("title"),
                "url": item.get("url"),
                "snippet": item.get("description"),
            }
        )
    return {"query": query, "results": results, "source": "brave"}


async def _ddg_search(query: str, count: int) -> dict[str, Any]:
    """Fallback: DuckDuckGo instant-answer API (no key required, limited results)."""
    url = "https://api.duckduckgo.com/"
    params = {"q": query, "format": "json", "no_html": "1", "no_redirect": "1"}
    async with httpx.AsyncClient(timeout=15.0) as client:
        resp = await client.get(url, params=params)
        resp.raise_for_status()
        data = resp.json()

    results = []
    # Abstract (top answer)
    if data.get("AbstractText"):
        results.append(
            {
                "title": data.get("Heading", query),
                "url": data.get("AbstractURL", ""),
                "snippet": data["AbstractText"],
            }
        )
    # Related topics
    for topic in data.get("RelatedTopics", [])[:count]:
        if isinstance(topic, dict) and topic.get("Text"):
            results.append(
                {
                    "title": topic.get("Text", "")[:80],
                    "url": topic.get("FirstURL", ""),
                    "snippet": topic.get("Text", ""),
                }
            )
        if len(results) >= count:
            break

    return {"query": query, "results": results, "source": "duckduckgo"}
