"""Tests for the DuckDuckGo-backed web_search tool."""

from __future__ import annotations

from app.services.tools.langchain_tools import ALL_PLUGIN_TOOLS
from app.services.tools.plugins import web_search as ws_module
from app.services.tools.plugins.web_search import (
    _TIME_RANGE_MAP,
    _format_results,
    build_web_search_tool,
)


def _install_fake_wrapper(monkeypatch, captured: dict, results=None, raise_exc=None):
    """Replace `DuckDuckGoSearchAPIWrapper` in the web_search module."""

    class FakeWrapper:
        def __init__(self, **kwargs):
            captured["init"] = kwargs

        def results(self, query, max_results=None):
            captured["query"] = query
            captured["max_results_call"] = max_results
            if raise_exc:
                raise raise_exc
            return results or []

    monkeypatch.setattr(ws_module, "DuckDuckGoSearchAPIWrapper", FakeWrapper)


# --------------------------------------------------------------------------
# Construction + hardcoded knob plumbing
# --------------------------------------------------------------------------


async def test_web_search_builds_with_hardcoded_knobs(monkeypatch):
    captured: dict = {}
    _install_fake_wrapper(
        monkeypatch,
        captured,
        results=[
            {"title": "T1", "link": "https://e.com", "snippet": "snip"},
        ],
    )

    tool = build_web_search_tool()
    result = await tool.ainvoke({"query": "test"})

    assert tool.name == "web_search"
    assert captured["init"]["region"] == "wt-wt"
    assert captured["init"]["safesearch"] == "moderate"
    assert captured["init"]["max_results"] == 5
    assert captured["init"]["backend"] == "api"
    assert captured["init"]["source"] == "text"
    assert captured["init"]["time"] is None
    assert "[1] T1" in result
    assert "https://e.com" in result


async def test_web_search_maps_time_range(monkeypatch):
    captured: dict = {}
    _install_fake_wrapper(monkeypatch, captured, results=[])
    tool = build_web_search_tool()

    await tool.ainvoke({"query": "x", "time_range": "day"})
    assert captured["init"]["time"] == "d"

    await tool.ainvoke({"query": "x", "time_range": "week"})
    assert captured["init"]["time"] == "w"

    await tool.ainvoke({"query": "x", "time_range": "month"})
    assert captured["init"]["time"] == "m"

    await tool.ainvoke({"query": "x", "time_range": "year"})
    assert captured["init"]["time"] == "y"

    await tool.ainvoke({"query": "x"})
    assert captured["init"]["time"] is None


def test_time_range_map_is_complete():
    assert set(_TIME_RANGE_MAP) == {"day", "week", "month", "year"}
    assert set(_TIME_RANGE_MAP.values()) == {"d", "w", "m", "y"}


# --------------------------------------------------------------------------
# Result formatting
# --------------------------------------------------------------------------


def test_format_results_empty():
    assert _format_results([]) == "No web results found."


def test_format_results_uses_ddg_field_names():
    out = _format_results(
        [
            {"title": "A", "link": "https://a.com", "snippet": "snip A"},
            {"title": "B", "link": "https://b.com", "snippet": "snip B"},
        ]
    )
    assert "[1] A" in out
    assert "https://a.com" in out
    assert "snip A" in out
    assert "[2] B" in out


def test_format_results_tolerates_missing_fields():
    # DDG occasionally returns partial dicts — must not raise.
    out = _format_results([{"title": "only-title"}])
    assert "[1] only-title" in out


# --------------------------------------------------------------------------
# Soft-fail on provider exception
# --------------------------------------------------------------------------


async def test_web_search_soft_fails_on_exception(monkeypatch):
    captured: dict = {}
    _install_fake_wrapper(monkeypatch, captured, raise_exc=RuntimeError("boom"))

    tool = build_web_search_tool()
    result = await tool.ainvoke({"query": "test"})

    assert isinstance(result, str)
    assert "unavailable" in result.lower()
    assert "RuntimeError" in result


# --------------------------------------------------------------------------
# Cross-cutting: schema + intent registry (preserved from old test)
# --------------------------------------------------------------------------


def test_web_search_is_exposed_to_agent():
    names = {tool.name for tool in ALL_PLUGIN_TOOLS}

    assert "web_search" in names
