from __future__ import annotations

import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch

from src.agent_tools import build_tool_context, default_tool_registry, execute_tool
from src.agent_types import AgentRuntimeConfig
from src.search_runtime import SearchRuntime


class FakeHTTPResponse:
    def __init__(self, payload: str) -> None:
        self.payload = payload

    def read(self) -> bytes:
        return self.payload.encode('utf-8')

    def __enter__(self) -> 'FakeHTTPResponse':
        return self

    def __exit__(self, exc_type, exc, tb) -> None:
        return None


class SearchRuntimeTests(unittest.TestCase):
    def test_provider_activation_persists_across_reload(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            workspace = Path(tmp_dir)
            (workspace / '.claw-search.json').write_text(
                (
                    '{"providers":['
                    '{"name":"primary","provider":"searxng","baseUrl":"http://127.0.0.1:8080"},'
                    '{"name":"backup","provider":"searxng","baseUrl":"http://127.0.0.2:8080"}'
                    ']}'
                ),
                encoding='utf-8',
            )
            runtime = SearchRuntime.from_workspace(workspace)
            report = runtime.activate_provider('backup')
            reloaded = SearchRuntime.from_workspace(workspace)

        self.assertEqual(report.provider_name, 'backup')
        self.assertIsNotNone(reloaded.current_provider())
        self.assertEqual(reloaded.current_provider().name, 'backup')

    def test_search_runtime_loads_searxng_provider_from_env(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            workspace = Path(tmp_dir)
            with patch.dict('os.environ', {'SEARXNG_BASE_URL': 'http://127.0.0.1:8888'}, clear=False):
                runtime = SearchRuntime.from_workspace(workspace)

        provider = runtime.current_provider()
        self.assertIsNotNone(provider)
        self.assertEqual(provider.name, 'searxng')
        self.assertEqual(provider.base_url, 'http://127.0.0.1:8888')

    def test_search_runtime_parses_searxng_results(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            workspace = Path(tmp_dir)
            (workspace / '.claw-search.json').write_text(
                '{"providers":[{"name":"local-search","provider":"searxng","baseUrl":"http://127.0.0.1:8080"}]}',
                encoding='utf-8',
            )
            runtime = SearchRuntime.from_workspace(workspace)
            with patch(
                'src.search_runtime.request.urlopen',
                return_value=FakeHTTPResponse(
                    '{"results":[{"title":"Alpha","url":"https://example.com/alpha","content":"Snippet"}]}'
                ),
            ):
                provider, results = runtime.search('alpha')

        self.assertEqual(provider.name, 'local-search')
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].title, 'Alpha')
        self.assertEqual(results[0].url, 'https://example.com/alpha')

    def test_search_runtime_parses_brave_results(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            workspace = Path(tmp_dir)
            (workspace / '.claw-search.json').write_text(
                '{"providers":[{"name":"brave-local","provider":"brave","baseUrl":"https://api.search.brave.com/res/v1/web/search","apiKeyEnv":"BRAVE_SEARCH_API_KEY"}]}',
                encoding='utf-8',
            )
            with patch.dict('os.environ', {'BRAVE_SEARCH_API_KEY': 'demo-key'}, clear=False):
                runtime = SearchRuntime.from_workspace(workspace)
                with patch(
                    'src.search_runtime.request.urlopen',
                    return_value=FakeHTTPResponse(
                        '{"web":{"results":[{"title":"Alpha","url":"https://example.com/alpha","description":"Snippet"}]}}'
                    ),
                ):
                    provider, results = runtime.search('alpha', provider_name='brave-local')

        self.assertEqual(provider.provider, 'brave')
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].snippet, 'Snippet')

    def test_web_search_tool_uses_search_runtime(self) -> None:
        registry = default_tool_registry()
        with tempfile.TemporaryDirectory() as tmp_dir:
            workspace = Path(tmp_dir)
            (workspace / '.claw-search.json').write_text(
                '{"providers":[{"name":"local-search","provider":"searxng","baseUrl":"http://127.0.0.1:8080"}]}',
                encoding='utf-8',
            )
            runtime = SearchRuntime.from_workspace(workspace)
            context = build_tool_context(
                AgentRuntimeConfig(cwd=workspace),
                tool_registry=registry,
                search_runtime=runtime,
            )
            with patch(
                'src.search_runtime.request.urlopen',
                return_value=FakeHTTPResponse(
                    '{"results":[{"title":"Alpha","url":"https://example.com/alpha","content":"Snippet"}]}'
                ),
            ):
                result = execute_tool(
                    registry,
                    'web_search',
                    {'query': 'alpha'},
                    context,
                )

        self.assertTrue(result.ok)
        self.assertIn('# Web Search', result.content)
        self.assertEqual(result.metadata.get('action'), 'web_search')
        self.assertEqual(result.metadata.get('provider'), 'local-search')
        self.assertEqual(result.metadata.get('result_count'), 1)
