"""
Tests for EvidenceBasedStrategy.

Tests cover:
- Initialization with dependencies
- Constraint extraction
- Candidate finding and scoring
- Evidence gathering
- Progress callbacks
- Error handling
"""

from unittest.mock import Mock, patch


class TestEvidenceBasedStrategyInit:
    """Tests for EvidenceBasedStrategy initialization."""

    def test_init_with_required_params(self):
        """Initialize with required parameters."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        assert strategy.model is mock_model
        assert strategy.search is mock_search
        assert strategy.max_iterations == 20
        assert strategy.confidence_threshold == 0.85
        assert strategy.candidate_limit == 10

    def test_init_with_custom_params(self):
        """Initialize with custom parameters."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
            max_iterations=10,
            confidence_threshold=0.9,
            candidate_limit=5,
            evidence_threshold=0.7,
        )

        assert strategy.max_iterations == 10
        assert strategy.confidence_threshold == 0.9
        assert strategy.candidate_limit == 5
        assert strategy.evidence_threshold == 0.7

    def test_init_creates_components(self):
        """Initialize creates required components."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        assert strategy.constraint_analyzer is not None
        assert strategy.evidence_evaluator is not None
        assert strategy.findings_repository is not None

    def test_init_with_settings_snapshot(self):
        """Initialize with settings snapshot."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()
        settings = {
            "search.iterations": {"value": 5},
        }

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
            settings_snapshot=settings,
        )

        assert strategy.settings_snapshot == settings

    def test_init_state_tracking(self):
        """Initialize state tracking lists."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        assert strategy.constraints == []
        assert strategy.candidates == []
        assert strategy.search_history == []
        assert strategy.iteration == 0


class TestAnalyzeTopic:
    """Tests for analyze_topic method."""

    def test_analyze_topic_extracts_constraints(self):
        """Analyze topic extracts constraints from query."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_search.run.return_value = []
        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Test response")

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
            max_iterations=1,
        )

        # Mock constraint analyzer to return test constraints
        with patch.object(
            strategy.constraint_analyzer, "extract_constraints", return_value=[]
        ) as mock_extract:
            strategy.analyze_topic("test query about specific topic")
            mock_extract.assert_called_once_with(
                "test query about specific topic"
            )

    def test_analyze_topic_calls_progress_callback(self):
        """Analyze topic calls progress callback."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_search.run.return_value = []
        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Test response")

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
            max_iterations=1,
        )

        callback = Mock()
        strategy.set_progress_callback(callback)

        with patch.object(
            strategy.constraint_analyzer, "extract_constraints", return_value=[]
        ):
            strategy.analyze_topic("test query")

        assert callback.call_count >= 1

    def test_analyze_topic_returns_result_dict(self):
        """Analyze topic returns expected result structure."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_search.run.return_value = []
        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Final answer")

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
            max_iterations=1,
        )

        with patch.object(
            strategy.constraint_analyzer, "extract_constraints", return_value=[]
        ):
            result = strategy.analyze_topic("test query")

        assert isinstance(result, dict)
        assert "current_knowledge" in result
        assert "findings" in result
        assert "iterations" in result
        assert "strategy" in result
        assert result["strategy"] == "evidence_based"


class TestConstraintHandling:
    """Tests for constraint handling methods."""

    def test_get_distinctive_constraints(self):
        """Get distinctive constraints prioritizes important types."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            Constraint,
            ConstraintType,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        # Create test constraints
        constraints = [
            Constraint(
                id="1",
                type=ConstraintType.PROPERTY,
                value="prop1",
                description="Property constraint",
                weight=0.5,
            ),
            Constraint(
                id="2",
                type=ConstraintType.LOCATION,
                value="loc1",
                description="Location constraint",
                weight=0.8,
            ),
            Constraint(
                id="3",
                type=ConstraintType.NAME_PATTERN,
                value="name1",
                description="Name pattern",
                weight=0.9,
            ),
        ]
        strategy.constraints = constraints

        distinctive = strategy._get_distinctive_constraints()

        # Name pattern should be prioritized
        assert len(distinctive) <= 3

    def test_create_candidate_search_query(self):
        """Create candidate search query from constraints."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            Constraint,
            ConstraintType,
        )

        mock_search = Mock()
        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="search query result")

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        constraints = [
            Constraint(
                id="1",
                type=ConstraintType.PROPERTY,
                value="test value",
                description="Test constraint",
                weight=0.8,
            ),
        ]

        query = strategy._create_candidate_search_query(constraints)

        assert isinstance(query, str)
        assert len(query) > 0


class TestCandidateHandling:
    """Tests for candidate handling methods."""

    def test_extract_candidates_from_results(self):
        """Extract candidates from search results."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()
        # First call for entity type, second for extraction
        mock_model.invoke.side_effect = [
            Mock(content="person"),
            Mock(content="CANDIDATE_1: John Smith\nCANDIDATE_2: Jane Doe"),
        ]

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        results = {
            "current_knowledge": "Information about John Smith and Jane Doe"
        }

        candidates = strategy._extract_candidates_from_results(
            results, "find person"
        )

        assert isinstance(candidates, list)

    def test_score_and_prune_candidates(self):
        """Score and prune candidates removes low scoring ones."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.candidates.base_candidate import (
            Candidate,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        # Create candidates with different scores
        candidate1 = Candidate(name="High Score")
        candidate1.score = 0.9
        candidate2 = Candidate(name="Low Score")
        candidate2.score = 0.1
        candidate3 = Candidate(name="Medium Score")
        candidate3.score = 0.5

        strategy.candidates = [candidate1, candidate2, candidate3]
        strategy.constraints = []

        strategy._score_and_prune_candidates()

        # Candidates should be sorted by score
        assert strategy.candidates[0].name == "High Score"

    def test_has_sufficient_answer_no_candidates(self):
        """Has sufficient answer returns False with no candidates."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        strategy.candidates = []

        assert strategy._has_sufficient_answer() is False

    def test_has_sufficient_answer_high_score_candidate(self):
        """Has sufficient answer returns True with high scoring candidate."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.candidates.base_candidate import (
            Candidate,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
            confidence_threshold=0.8,
        )

        candidate = Candidate(name="Top Answer")
        candidate.score = 0.95
        strategy.candidates = [candidate]
        strategy.constraints = []  # No critical constraints

        assert strategy._has_sufficient_answer() is True


class TestEvidenceGathering:
    """Tests for evidence gathering methods."""

    def test_gather_evidence_round_with_candidates(self):
        """Gather evidence round processes candidates."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.candidates.base_candidate import (
            Candidate,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            Constraint,
            ConstraintType,
        )

        mock_search = Mock()
        mock_search.run.return_value = []
        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="search query")

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        candidate = Candidate(name="Test Candidate")
        strategy.candidates = [candidate]

        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            value="test",
            description="Test constraint",
            weight=0.8,
        )
        strategy.constraints = [constraint]

        # Mock evidence evaluator
        with patch.object(
            strategy.evidence_evaluator,
            "extract_evidence",
            return_value=Mock(
                confidence=0.7, type=Mock(value="inference"), claim="Test claim"
            ),
        ):
            strategy._gather_evidence_round()

        assert len(candidate.evidence) > 0

    def test_calculate_evidence_coverage(self):
        """Calculate evidence coverage returns correct percentage."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.candidates.base_candidate import (
            Candidate,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            Constraint,
            ConstraintType,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        # Create candidate with some evidence
        candidate = Candidate(name="Test")
        candidate.evidence = {"c1": Mock()}
        strategy.candidates = [candidate]

        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            value="test",
            description="Test",
            weight=0.5,
        )
        strategy.constraints = [constraint]

        coverage = strategy._calculate_evidence_coverage()

        assert 0 <= coverage <= 1.0


class TestSearchExecution:
    """Tests for search execution methods."""

    def test_execute_search_direct_mode(self):
        """Execute search in direct mode."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_search.run.return_value = [
            {"title": "Result 1", "snippet": "Content 1"},
            {"title": "Result 2", "snippet": "Content 2"},
        ]
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )
        strategy.use_direct_search = True

        result = strategy._execute_search("test query")

        assert "current_knowledge" in result
        assert "findings" in result
        mock_search.run.assert_called_once_with("test query")

    def test_execute_search_updates_history(self):
        """Execute search updates search history."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_search.run.return_value = []
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )
        strategy.use_direct_search = True

        strategy._execute_search("test query")

        assert len(strategy.search_history) == 1
        assert strategy.search_history[0]["query"] == "test query"


class TestFormattingMethods:
    """Tests for formatting helper methods."""

    def test_format_initial_analysis(self):
        """Format initial analysis creates readable output."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            Constraint,
            ConstraintType,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            value="test",
            description="Test constraint",
            weight=0.8,
        )
        strategy.constraints = [constraint]

        analysis = strategy._format_initial_analysis("test query")

        assert "test query" in analysis
        assert "Evidence-Based" in analysis

    def test_format_iteration_summary(self):
        """Format iteration summary shows candidate status."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.candidates.base_candidate import (
            Candidate,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        candidate = Candidate(name="Test Candidate")
        candidate.score = 0.75
        strategy.candidates = [candidate]
        strategy.constraints = []
        strategy.iteration = 1
        strategy.max_iterations = 5
        strategy.search_history = []

        summary = strategy._format_iteration_summary()

        assert "Iteration 1" in summary
        assert "Test Candidate" in summary

    def test_format_evidence_summary_no_candidates(self):
        """Format evidence summary handles no candidates."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        strategy.candidates = []

        summary = strategy._format_evidence_summary()

        assert "No candidates found" in summary


class TestHelperMethods:
    """Tests for utility helper methods."""

    def test_get_timestamp(self):
        """Get timestamp returns ISO format string."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        timestamp = strategy._get_timestamp()

        assert isinstance(timestamp, str)
        # ISO format should contain T separator
        assert "T" in timestamp

    def test_get_iteration_status_no_candidates(self):
        """Get iteration status with no candidates."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        strategy.candidates = []

        status = strategy._get_iteration_status()

        assert "initial candidates" in status.lower()

    def test_get_iteration_status_high_score(self):
        """Get iteration status with high scoring candidate."""
        from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
            EvidenceBasedStrategy,
        )
        from local_deep_research.advanced_search_system.candidates.base_candidate import (
            Candidate,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = EvidenceBasedStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=[],
        )

        candidate = Candidate(name="Top")
        candidate.score = 0.9
        strategy.candidates = [candidate]

        status = strategy._get_iteration_status()

        assert "verifying" in status.lower()
