"""
Tests targeting specific uncovered branches in browsecomp_question.py.

Covers:
- Lines 318-336: name+descriptor combo fallback in _generate_progressive_searches (iteration>5)
- Line 191, 199: Location-based searches in _generate_initial_searches
- Line 252: Non-failing strategy instruction
- Line 363: Unlimited previous_searches_limit
"""

from unittest.mock import Mock

from local_deep_research.advanced_search_system.questions.browsecomp_question import (
    BrowseCompQuestionGenerator,
)


def _make_generator(**kwargs):
    model = Mock()
    model.invoke.return_value = Mock(content="search result")
    return BrowseCompQuestionGenerator(model, **kwargs)


# ---------------------------------------------------------------------------
# Lines 318-336: name+descriptor combo loop (iteration > 5)
# ---------------------------------------------------------------------------
class TestProgressiveSearchesCombos:
    def test_generates_name_descriptor_combinations_when_iteration_gt_5(self):
        """When iteration>5, the else branch combines names with descriptors."""
        gen = _make_generator()
        gen.model.invoke.return_value = Mock(content="only one")
        entities = {
            "temporal": ["2020"],
            "numerical": [],
            "names": ["Einstein", "Newton"],
            "locations": [],
            "descriptors": ["physicist", "gravity"],
        }
        searches = gen._generate_progressive_searches(
            query="Test",
            current_knowledge="",
            entities=entities,
            questions_by_iteration={},
            results_by_iteration={},
            num_questions=5,
            iteration=6,  # >5 to hit the else branch
        )
        # Should have filled up via name+descriptor combos
        combos = [
            s for s in searches if any(n in s for n in ["Einstein", "Newton"])
        ]
        assert len(combos) >= 1

    def test_breaks_when_no_names_or_descriptors(self):
        """When no names/descriptors, added_any stays False and loop breaks."""
        gen = _make_generator()
        gen.model.invoke.return_value = Mock(content="only one")
        entities = {
            "temporal": [],
            "numerical": [],
            "names": [],
            "locations": [],
            "descriptors": [],
        }
        searches = gen._generate_progressive_searches(
            query="Test",
            current_knowledge="",
            entities=entities,
            questions_by_iteration={},
            results_by_iteration={},
            num_questions=5,
            iteration=6,
        )
        # Should have only the model-generated search since combos can't be made
        assert len(searches) <= 5

    def test_skips_already_searched_combos(self):
        """Combos that were already searched are skipped."""
        gen = _make_generator()
        gen.model.invoke.return_value = Mock(content="only one")
        entities = {
            "temporal": [],
            "numerical": [],
            "names": ["Einstein"],
            "locations": [],
            "descriptors": ["physics"],
        }
        # Mark "Einstein physics" as already searched
        questions_by_iteration = {1: ["Einstein physics"]}
        searches = gen._generate_progressive_searches(
            query="Test",
            current_knowledge="",
            entities=entities,
            questions_by_iteration=questions_by_iteration,
            results_by_iteration={},
            num_questions=3,
            iteration=6,
        )
        # "Einstein physics" should not appear again since it was searched
        assert isinstance(searches, list)


# ---------------------------------------------------------------------------
# Lines 191, 196-202: Location searches in _generate_initial_searches
# ---------------------------------------------------------------------------
class TestInitialSearchesLocationBranches:
    def test_location_with_descriptor_no_names(self):
        """Locations + descriptors but no names → location+descriptor search."""
        gen = _make_generator()
        entities = {
            "temporal": [],
            "numerical": [],
            "names": [],
            "locations": ["Paris", "London"],
            "descriptors": ["historic"],
        }
        searches = gen._generate_initial_searches("Original query", entities, 5)
        assert any("Paris" in s for s in searches)
        # Should also have "Paris historic"
        assert any("Paris" in s and "historic" in s for s in searches)

    def test_location_only_no_descriptors(self):
        """Locations but no descriptors → location-only search."""
        gen = _make_generator()
        entities = {
            "temporal": [],
            "numerical": [],
            "names": [],
            "locations": ["Tokyo"],
            "descriptors": [],
        }
        searches = gen._generate_initial_searches("Original query", entities, 5)
        assert "Tokyo" in searches

    def test_temporal_with_descriptors_no_names(self):
        """Temporal + descriptors but no names → uses descriptor as key_term."""
        gen = _make_generator()
        entities = {
            "temporal": ["2020", "2021"],
            "numerical": [],
            "names": [],
            "locations": [],
            "descriptors": ["conference"],
        }
        searches = gen._generate_initial_searches("Original query", entities, 5)
        # Should use descriptor as key_term for year searches
        assert any("conference" in s for s in searches)


# ---------------------------------------------------------------------------
# Line 252: Non-failing strategy instruction
# ---------------------------------------------------------------------------
class TestNonFailingStrategy:
    def test_non_failing_strategy_when_few_zero_results(self):
        """When fewer than 3 zero-result iterations, strategy is non-failing."""
        gen = _make_generator()
        gen.model.invoke.return_value = Mock(content="systematic search")
        entities = {
            "temporal": [],
            "numerical": [],
            "names": [],
            "locations": [],
            "descriptors": [],
        }
        # Only 1 zero-result iteration (not >= 3)
        results_by_iteration = {1: 5, 2: 3, 3: 0, 4: 10}
        gen._generate_progressive_searches(
            query="Test",
            current_knowledge="",
            entities=entities,
            questions_by_iteration={},
            results_by_iteration=results_by_iteration,
            num_questions=1,
            iteration=5,
        )
        # Check the prompt doesn't contain the "TOO NARROW" warning
        call_args = gen.model.invoke.call_args[0][0]
        assert "NARROW" not in call_args
        assert (
            "combine" in call_args.lower()
            or "systematically" in call_args.lower()
        )


# ---------------------------------------------------------------------------
# Line 363: Unlimited previous_searches_limit
# ---------------------------------------------------------------------------
class TestFormatPreviousSearchesUnlimited:
    def test_unlimited_when_limit_is_none(self):
        """When previous_searches_limit is None, all searches are shown."""
        gen = _make_generator(previous_searches_limit=None)
        questions = {i: [f"query{i}"] for i in range(20)}
        results = {}
        formatted = gen._format_previous_searches(questions, results)
        lines = [line for line in formatted.strip().split("\n") if line]
        assert len(lines) == 20

    def test_unlimited_when_limit_is_zero(self):
        """When previous_searches_limit is 0 (falsy), all searches are shown."""
        gen = _make_generator(previous_searches_limit=0)
        questions = {i: [f"query{i}"] for i in range(15)}
        results = {}
        formatted = gen._format_previous_searches(questions, results)
        lines = [line for line in formatted.strip().split("\n") if line]
        assert len(lines) == 15

    def test_limited_output_truncates(self):
        """When previous_searches_limit is set, output is truncated."""
        gen = _make_generator(previous_searches_limit=3)
        questions = {i: [f"query{i}"] for i in range(10)}
        results = {}
        formatted = gen._format_previous_searches(questions, results)
        lines = [line for line in formatted.strip().split("\n") if line]
        assert len(lines) <= 3
