"""
Pure-logic tests for EvidenceBasedStrategy formatting methods.

Tests _format_evidence_summary and _format_final_synthesis output structure,
constraint satisfaction breakdown, and edge cases — no LLM or search calls.
"""

from unittest.mock import Mock

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,
)
from local_deep_research.advanced_search_system.evidence.base_evidence import (
    Evidence,
    EvidenceType,
)
from local_deep_research.advanced_search_system.strategies.evidence_based_strategy import (
    EvidenceBasedStrategy,
)


def _evidence(confidence=0.8, claim="test claim"):
    return Evidence(
        type=EvidenceType.DIRECT_STATEMENT,
        confidence=confidence,
        claim=claim,
        source="test source",
    )


def _constraint(cid, desc="test constraint"):
    return Constraint(
        id=cid,
        type=ConstraintType.PROPERTY,
        description=desc,
        value=desc,
        weight=1.0,
    )


def _candidate(name, evidence_map=None, score=0.8):
    c = Candidate(name=name)
    c.evidence = evidence_map or {}
    c.score = score
    return c


def _make_strategy(candidates=None, constraints=None, evidence_threshold=0.5):
    """Build a minimal Mock for EvidenceBasedStrategy."""
    s = Mock(spec=[])
    s.candidates = candidates or []
    s.constraints = constraints or []
    s.evidence_threshold = evidence_threshold
    s.iteration = 3
    s.max_iterations = 5
    s.search_history = [{"query": "q1"}, {"query": "q2"}]
    s.findings = []
    # Bind _format_evidence_summary so _format_final_synthesis can call it
    s._format_evidence_summary = (
        EvidenceBasedStrategy._format_evidence_summary.__get__(s)
    )
    return s


# ---------------------------------------------------------------------------
# _format_evidence_summary
# ---------------------------------------------------------------------------


class TestFormatEvidenceSummary:
    """Verify evidence summary formatting."""

    def test_no_candidates(self):
        """No candidates returns fallback message."""
        s = _make_strategy()
        result = EvidenceBasedStrategy._format_evidence_summary(s)
        assert result == "No candidates found"

    def test_single_candidate_with_evidence(self):
        """Candidate with evidence shows claim and confidence."""
        c1 = _constraint("c1", "height check")
        cand = _candidate("Mount Rainier", {"c1": _evidence(0.9, "14,411 ft")})
        s = _make_strategy(candidates=[cand], constraints=[c1])
        result = EvidenceBasedStrategy._format_evidence_summary(s)
        assert "Mount Rainier" in result
        assert "14,411 ft" in result
        assert "0.90" in result

    def test_missing_evidence_shows_no_evidence(self):
        """Constraint without evidence shows 'No evidence'."""
        c1 = _constraint("c1", "location check")
        cand = _candidate("Alice", {})
        s = _make_strategy(candidates=[cand], constraints=[c1])
        result = EvidenceBasedStrategy._format_evidence_summary(s)
        assert "No evidence" in result

    def test_shows_top_two_candidates(self):
        """Only first two candidates are shown."""
        c1 = _constraint("c1")
        cands = [
            _candidate("A", {"c1": _evidence()}, score=0.9),
            _candidate("B", {"c1": _evidence()}, score=0.8),
            _candidate("C", {"c1": _evidence()}, score=0.7),
        ]
        s = _make_strategy(candidates=cands, constraints=[c1])
        result = EvidenceBasedStrategy._format_evidence_summary(s)
        assert "A" in result
        assert "B" in result
        assert "C" not in result


# ---------------------------------------------------------------------------
# _format_final_synthesis
# ---------------------------------------------------------------------------


class TestFormatFinalSynthesis:
    """Verify final synthesis formatting."""

    def test_no_candidates_fallback(self):
        """No candidates shows fallback messages."""
        s = _make_strategy()
        result = EvidenceBasedStrategy._format_final_synthesis(
            s, "No answer", 0
        )
        assert "No candidates found" in result
        assert "No answer" in result

    def test_with_candidates_shows_satisfaction(self):
        """With candidates, shows constraint satisfaction count."""
        c1 = _constraint("c1", "height")
        c2 = _constraint("c2", "location")
        cand = _candidate(
            "Peak",
            {"c1": _evidence(0.9), "c2": _evidence(0.3)},
            score=0.7,
        )
        s = _make_strategy(
            candidates=[cand],
            constraints=[c1, c2],
            evidence_threshold=0.5,
        )
        result = EvidenceBasedStrategy._format_final_synthesis(s, "Peak", 70)
        # c1 is above threshold, c2 is below
        assert "Satisfied 1/2" in result

    def test_confidence_percentage_shown(self):
        """Confidence percentage appears in output."""
        c1 = _constraint("c1")
        cand = _candidate("X", {"c1": _evidence(0.8)}, score=0.8)
        s = _make_strategy(candidates=[cand], constraints=[c1])
        result = EvidenceBasedStrategy._format_final_synthesis(s, "X", 85)
        assert "85%" in result

    def test_constraint_breakdown_checkmarks(self):
        """Satisfied constraints get checkmark, unsatisfied get cross."""
        c1 = _constraint("c1", "passes")
        c2 = _constraint("c2", "fails")
        cand = _candidate(
            "Test",
            {"c1": _evidence(0.9)},  # c2 has no evidence
            score=0.5,
        )
        s = _make_strategy(
            candidates=[cand],
            constraints=[c1, c2],
            evidence_threshold=0.5,
        )
        result = EvidenceBasedStrategy._format_final_synthesis(s, "Test", 50)
        assert "✓" in result
        assert "✗" in result

    def test_below_threshold_warning(self):
        """Evidence below threshold gets warning marker."""
        c1 = _constraint("c1", "weak evidence")
        cand = _candidate(
            "Test",
            {"c1": _evidence(0.3)},
            score=0.3,
        )
        s = _make_strategy(
            candidates=[cand],
            constraints=[c1],
            evidence_threshold=0.5,
        )
        result = EvidenceBasedStrategy._format_final_synthesis(s, "Test", 30)
        assert "⚠" in result
        assert "below threshold" in result

    def test_iteration_count_shown(self):
        """Iteration count is included."""
        c1 = _constraint("c1")
        cand = _candidate("X", {"c1": _evidence()}, score=0.8)
        s = _make_strategy(candidates=[cand], constraints=[c1])
        result = EvidenceBasedStrategy._format_final_synthesis(s, "X", 80)
        assert "3/5" in result

    def test_top_candidates_listed(self):
        """Top 3 candidates are listed with scores."""
        c1 = _constraint("c1")
        cands = [
            _candidate("Alpha", {"c1": _evidence()}, score=0.9),
            _candidate("Beta", {"c1": _evidence()}, score=0.8),
            _candidate("Gamma", {"c1": _evidence()}, score=0.7),
            _candidate("Delta", {"c1": _evidence()}, score=0.6),
        ]
        s = _make_strategy(candidates=cands, constraints=[c1])
        result = EvidenceBasedStrategy._format_final_synthesis(s, "Alpha", 90)
        assert "Alpha" in result
        assert "Beta" in result
        assert "Gamma" in result
        # Delta (4th) might appear in evidence summary but not in top candidates list
