"""
FrankenClaw — search_web tool

Queries a SearXNG instance you control. Returns structured results:
title, url, snippet.

Configure the SearXNG endpoint in `~/.frankenclaw/config.json`:

    {"searxng_url": "http://localhost:8080"}

Or use the `docker-exec://<container>:<port>` scheme to reach a SearXNG
that lives inside a Docker container with no host-port mapping:

    {"searxng_url": "docker-exec://my-searxng:8080"}

SearXNG is open-source and free — see https://searxng.github.io to run
your own. There's no shared default; you bring your own.
"""

import json
import subprocess
from urllib.parse import quote_plus

from config import load_config


def _query_searxng(query: str, num_results: int) -> list[dict]:
    """Execute a search query against the configured SearXNG endpoint."""
    cfg = load_config()
    searxng_url = cfg["searxng_url"]

    # Parse docker-exec:// scheme — runs `docker exec <container> curl ...`
    if searxng_url.startswith("docker-exec://"):
        parts = searxng_url.replace("docker-exec://", "").split(":")
        container = parts[0]
        port = parts[1] if len(parts) > 1 else "8080"

        encoded_query = quote_plus(query)
        url = f"http://localhost:{port}/search?q={encoded_query}&format=json&pageno=1"
        result = subprocess.run(
            ["docker", "exec", container, "curl", "-s", url],
            capture_output=True,
            text=True,
            timeout=15,
        )

        if result.returncode != 0:
            raise RuntimeError(
                f"SearXNG query failed (exit {result.returncode}): {result.stderr}"
            )

        data = json.loads(result.stdout)
    else:
        # Direct HTTP URL
        import httpx
        resp = httpx.get(
            searxng_url + "/search",
            params={"q": query, "format": "json", "pageno": 1},
            timeout=15,
        )
        resp.raise_for_status()
        data = resp.json()

    results = []
    for item in data.get("results", [])[:num_results]:
        results.append({
            "title": item.get("title", ""),
            "url": item.get("url", ""),
            "snippet": item.get("content", ""),
        })

    return results


async def search_web(query: str, num_results: int = 10) -> str:
    """
    Search the web using SearXNG.

    Args:
        query: The search query string.
        num_results: Maximum number of results to return (default 10).

    Returns:
        JSON array of search results with title, url, and snippet.
    """
    max_results = load_config().get("max_search_results", 10)
    num_results = min(num_results, max_results)

    results = _query_searxng(query, num_results)

    return json.dumps(results, indent=2)
