"""High-value pure logic tests for MetaSearchEngine.

Tests focus on _get_search_config() and analyze_query() without network calls.
"""

from unittest.mock import Mock, patch


from local_deep_research.web_search_engines.engines.meta_search_engine import (
    MetaSearchEngine,
)

MODULE = "local_deep_research.web_search_engines.engines.meta_search_engine"


def _make_engine(available_engines=None, settings_snapshot=None, llm=None):
    """Create a MetaSearchEngine instance bypassing __init__."""
    with patch.object(
        MetaSearchEngine, "__init__", lambda self, *a, **kw: None
    ):
        engine = MetaSearchEngine.__new__(MetaSearchEngine)
    engine.available_engines = available_engines or []
    engine.settings_snapshot = settings_snapshot
    engine.llm = llm
    engine.engine_cache = {}
    engine.max_results = 10
    engine.max_filtered_results = None
    engine.use_api_key_services = True
    return engine


class TestGetSearchConfig:
    """Tests for MetaSearchEngine._get_search_config() (delegates to get_available_engines)."""

    def test_returns_empty_dict_when_no_settings_snapshot(self):
        engine = _make_engine(settings_snapshot=None)
        result = engine._get_search_config()
        assert result == {}

    def test_returns_empty_dict_when_settings_snapshot_is_empty(self):
        engine = _make_engine(settings_snapshot={})
        result = engine._get_search_config()
        assert result == {}

    def test_delegates_to_get_available_engines(self):
        expected = {
            "brave": {
                "api_key": "test-key-123",
                "module_path": ".engines.search_engine_brave",
                "class_name": "BraveSearchEngine",
            },
        }
        engine = _make_engine(settings_snapshot={"search.max_results": 10})
        engine.use_api_key_services = True
        with patch(f"{MODULE}.get_available_engines", return_value=expected):
            config = engine._get_search_config()
        assert config == expected


class TestAnalyzeQuerySpecializedDomains:
    """Tests for analyze_query() heuristic matching of specialized domains."""

    def test_scientific_paper_returns_arxiv_pubmed_wikipedia(self):
        engine = _make_engine(
            available_engines=["arxiv", "pubmed", "wikipedia", "searxng"]
        )
        result = engine.analyze_query("find a scientific paper on transformers")
        assert result == ["arxiv", "pubmed", "wikipedia"]

    def test_medical_research_returns_pubmed_searxng(self):
        engine = _make_engine(
            available_engines=["arxiv", "pubmed", "searxng", "wikipedia"]
        )
        result = engine.analyze_query("medical research on cancer treatment")
        assert result == ["pubmed", "searxng"]

    def test_clinical_returns_pubmed_searxng(self):
        engine = _make_engine(available_engines=["pubmed", "searxng", "brave"])
        result = engine.analyze_query("clinical trials for diabetes drugs")
        assert result == ["pubmed", "searxng"]

    def test_github_returns_github_searxng(self):
        engine = _make_engine(available_engines=["github", "searxng", "brave"])
        result = engine.analyze_query("github repo for machine learning")
        assert result == ["github", "searxng"]

    def test_code_query_returns_github_searxng(self):
        engine = _make_engine(available_engines=["github", "searxng", "arxiv"])
        result = engine.analyze_query("python code for sorting algorithms")
        assert result == ["github", "searxng"]

    def test_programming_query_returns_github_searxng(self):
        engine = _make_engine(
            available_engines=["github", "searxng", "wikipedia"]
        )
        result = engine.analyze_query("programming tutorial for rust")
        assert result == ["github", "searxng"]

    def test_repository_query_returns_github_searxng(self):
        engine = _make_engine(available_engines=["github", "searxng"])
        result = engine.analyze_query("best repository for NLP models")
        assert result == ["github", "searxng"]

    def test_specialized_domain_filters_unavailable_engines(self):
        """If specialized engines aren't available, skip to next heuristic."""
        engine = _make_engine(
            available_engines=["searxng", "brave"],
        )
        engine._get_search_config = Mock(
            return_value={
                "searxng": {"reliability": 0.9},
                "brave": {"reliability": 0.5},
            }
        )
        result = engine.analyze_query("scientific paper on quantum computing")
        assert result[0] == "searxng"

    def test_specialized_domain_partial_availability(self):
        """Only available engines from the specialized list are returned."""
        engine = _make_engine(
            available_engines=["wikipedia", "brave", "searxng"]
        )
        result = engine.analyze_query("scientific paper on dark matter")
        assert result == ["wikipedia"]

    def test_case_insensitive_matching(self):
        engine = _make_engine(available_engines=["pubmed", "searxng"])
        result = engine.analyze_query("MEDICAL RESEARCH on hypertension")
        assert result == ["pubmed", "searxng"]


class TestAnalyzeQueryArxivPubmedPriority:
    """Tests for arxiv/pubmed keyword prioritization in analyze_query()."""

    def test_arxiv_in_query_prioritizes_arxiv(self):
        engine = _make_engine(available_engines=["searxng", "arxiv", "brave"])
        result = engine.analyze_query("search arxiv for attention mechanisms")
        assert result[0] == "arxiv"
        assert "searxng" in result
        assert "brave" in result

    def test_arxiv_in_query_but_not_available_falls_through(self):
        engine = _make_engine(
            available_engines=["searxng", "brave"],
        )
        engine._get_search_config = Mock(
            return_value={
                "searxng": {"reliability": 0.9},
                "brave": {"reliability": 0.5},
            }
        )
        result = engine.analyze_query("look on arxiv for papers")
        assert result[0] == "searxng"

    def test_pubmed_in_query_prioritizes_pubmed(self):
        engine = _make_engine(available_engines=["searxng", "pubmed", "brave"])
        result = engine.analyze_query("search pubmed for drug interactions")
        assert result[0] == "pubmed"
        assert "searxng" in result
        assert "brave" in result

    def test_pubmed_in_query_but_not_available_falls_through(self):
        engine = _make_engine(
            available_engines=["searxng", "brave"],
        )
        engine._get_search_config = Mock(
            return_value={
                "searxng": {"reliability": 0.9},
                "brave": {"reliability": 0.5},
            }
        )
        result = engine.analyze_query("find pubmed articles")
        assert result[0] == "searxng"


class TestAnalyzeQueryGeneralAndFallback:
    """Tests for general query handling and fallback logic in analyze_query()."""

    def test_general_query_with_searxng_returns_searxng_first(self):
        engine = _make_engine(
            available_engines=["brave", "searxng", "wikipedia"],
        )
        engine._get_search_config = Mock(
            return_value={
                "brave": {"reliability": 0.5},
                "wikipedia": {"reliability": 0.8},
                "searxng": {"reliability": 0.9},
            }
        )
        result = engine.analyze_query("what is the weather today")
        assert result[0] == "searxng"
        assert "searxng" not in result[1:]  # no duplicate

    def test_general_query_without_searxng_uses_reliability(self):
        engine = _make_engine(
            available_engines=["brave", "wikipedia"],
            llm=None,
        )
        engine._get_search_config = Mock(
            return_value={
                "brave": {"reliability": 0.9},
                "wikipedia": {"reliability": 0.7},
            }
        )
        result = engine.analyze_query("what is the capital of France")
        assert result[0] == "brave"
        assert result[1] == "wikipedia"

    def test_reliability_sorting_with_no_reliability_keys(self):
        """Engines with no reliability config get default 0."""
        engine = _make_engine(
            available_engines=["brave", "wikipedia"],
            llm=None,
        )
        engine._get_search_config = Mock(return_value={})
        result = engine.analyze_query("generic search query")
        assert set(result) == {"brave", "wikipedia"}

    def test_empty_engines_returns_empty_list(self):
        """With no available engines, analyze_query returns empty list."""
        engine = _make_engine(
            available_engines=[],
            llm=None,
        )
        result = engine.analyze_query("anything")
        assert result == []

    def test_searxng_general_query_sorts_remaining_by_reliability(self):
        engine = _make_engine(
            available_engines=["brave", "searxng", "wikipedia", "arxiv"],
        )
        engine._get_search_config = Mock(
            return_value={
                "brave": {"reliability": 0.5},
                "wikipedia": {"reliability": 0.8},
                "arxiv": {"reliability": 0.3},
                "searxng": {"reliability": 0.9},
            }
        )
        result = engine.analyze_query("latest news on AI")
        assert result[0] == "searxng"
        # Remaining sorted by reliability descending
        assert result[1] == "wikipedia"
        assert result[2] == "brave"
        assert result[3] == "arxiv"
