"""
Extended tests for RejectionEngine - Constraint-based candidate filtering.

Tests cover:
- RejectionResult dataclass
- RejectionEngine initialization
- should_reject_candidate method
- check_all_constraints method
- Threshold logic
- Edge cases

These tests import and test the ACTUAL RejectionEngine class.
"""

from unittest.mock import patch

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.constraint_checking.rejection_engine import (
    RejectionEngine,
    RejectionResult,
)
from local_deep_research.advanced_search_system.constraint_checking.evidence_analyzer import (
    ConstraintEvidence,
)


class TestRejectionResultDataclass:
    """Tests for RejectionResult dataclass."""

    def test_has_should_reject(self):
        """RejectionResult should have should_reject field."""
        result = RejectionResult(
            should_reject=True,
            reason="Test reason",
            constraint_value="value",
            positive_confidence=0.3,
            negative_confidence=0.7,
        )
        assert result.should_reject is True

    def test_has_reason(self):
        """RejectionResult should have reason field."""
        result = RejectionResult(
            should_reject=True,
            reason="High negative evidence",
            constraint_value="value",
            positive_confidence=0.3,
            negative_confidence=0.7,
        )
        assert result.reason == "High negative evidence"

    def test_has_constraint_value(self):
        """RejectionResult should have constraint_value field."""
        result = RejectionResult(
            should_reject=False,
            reason="OK",
            constraint_value="test_value",
            positive_confidence=0.6,
            negative_confidence=0.2,
        )
        assert result.constraint_value == "test_value"

    def test_has_positive_confidence(self):
        """RejectionResult should have positive_confidence field."""
        result = RejectionResult(
            should_reject=False,
            reason="OK",
            constraint_value="value",
            positive_confidence=0.6,
            negative_confidence=0.2,
        )
        assert result.positive_confidence == 0.6

    def test_has_negative_confidence(self):
        """RejectionResult should have negative_confidence field."""
        result = RejectionResult(
            should_reject=True,
            reason="Test",
            constraint_value="value",
            positive_confidence=0.2,
            negative_confidence=0.4,
        )
        assert result.negative_confidence == 0.4


class TestRejectionEngineInitialization:
    """Tests for RejectionEngine initialization."""

    def test_default_negative_threshold(self):
        """Default negative_threshold should be 0.25."""
        engine = RejectionEngine()
        assert engine.negative_threshold == 0.25

    def test_default_positive_threshold(self):
        """Default positive_threshold should be 0.4."""
        engine = RejectionEngine()
        assert engine.positive_threshold == 0.4

    def test_custom_negative_threshold(self):
        """Should accept custom negative_threshold."""
        engine = RejectionEngine(negative_threshold=0.3)
        assert engine.negative_threshold == 0.3

    def test_custom_positive_threshold(self):
        """Should accept custom positive_threshold."""
        engine = RejectionEngine(positive_threshold=0.5)
        assert engine.positive_threshold == 0.5

    def test_both_custom_thresholds(self):
        """Should accept both custom thresholds."""
        engine = RejectionEngine(negative_threshold=0.2, positive_threshold=0.6)
        assert engine.negative_threshold == 0.2
        assert engine.positive_threshold == 0.6


class TestShouldRejectCandidate:
    """Tests for should_reject_candidate method."""

    def test_no_evidence_does_not_reject(self):
        """Should not reject when no evidence available."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test Candidate")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test constraint",
            value="test_value",
        )

        result = engine.should_reject_candidate(candidate, constraint, [])

        assert result.should_reject is False
        assert result.reason == "No evidence available"
        assert result.positive_confidence == 0.0
        assert result.negative_confidence == 0.0

    def test_calculates_average_positive(self):
        """Should calculate average positive confidence."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.6,
                negative_confidence=0.1,
                uncertainty=0.3,
                evidence_text="text1",
                source="s1",
            ),
            ConstraintEvidence(
                positive_confidence=0.8,
                negative_confidence=0.1,
                uncertainty=0.1,
                evidence_text="text2",
                source="s2",
            ),
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.2,
                uncertainty=0.3,
                evidence_text="text3",
                source="s3",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        # Average: (0.6 + 0.8 + 0.5) / 3 = 0.633
        assert abs(result.positive_confidence - 0.633) < 0.01

    def test_calculates_average_negative(self):
        """Should calculate average negative confidence."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.2,
                uncertainty=0.3,
                evidence_text="text1",
                source="s1",
            ),
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.1,
                uncertainty=0.4,
                evidence_text="text2",
                source="s2",
            ),
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.3,
                uncertainty=0.2,
                evidence_text="text3",
                source="s3",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        # Average: (0.2 + 0.1 + 0.3) / 3 = 0.2
        assert abs(result.negative_confidence - 0.2) < 0.001

    def test_rejects_high_negative_evidence(self):
        """Should reject when negative evidence exceeds threshold."""
        engine = RejectionEngine(negative_threshold=0.25)
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="test_value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.3,  # Above 0.25 threshold
                uncertainty=0.2,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.should_reject is True
        assert "High negative evidence" in result.reason

    def test_rejects_low_positive_evidence(self):
        """Should reject when positive evidence below threshold."""
        engine = RejectionEngine(positive_threshold=0.4)
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="test_value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.3,  # Below 0.4 threshold
                negative_confidence=0.2,  # Below negative threshold
                uncertainty=0.5,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.should_reject is True
        assert "Insufficient positive evidence" in result.reason

    def test_accepts_when_constraints_satisfied(self):
        """Should accept when constraints satisfied."""
        engine = RejectionEngine(
            negative_threshold=0.25, positive_threshold=0.4
        )
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="test_value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.6,  # Above 0.4
                negative_confidence=0.1,  # Below 0.25
                uncertainty=0.3,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.should_reject is False
        assert result.reason == "Constraints satisfied"

    def test_primary_rule_takes_precedence(self):
        """Primary rejection rule (high negative) should take precedence."""
        engine = RejectionEngine(
            negative_threshold=0.25, positive_threshold=0.4
        )
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="test_value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.3,  # Would trigger secondary rule
                negative_confidence=0.5,  # Would trigger primary rule
                uncertainty=0.2,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.should_reject is True
        assert "High negative evidence" in result.reason


class TestCheckAllConstraints:
    """Tests for check_all_constraints method.

    Note: The Constraint dataclass is not hashable, so we test the underlying
    should_reject_candidate method instead, which the check_all_constraints
    method calls for each constraint.
    """

    def test_multiple_constraints_all_pass(self):
        """Should not reject when multiple constraints all pass via should_reject_candidate."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")

        constraints_and_evidence = [
            (
                Constraint(
                    id="c1",
                    type=ConstraintType.PROPERTY,
                    description="Constraint 1",
                    value="value1",
                ),
                [
                    ConstraintEvidence(
                        positive_confidence=0.8,
                        negative_confidence=0.1,
                        uncertainty=0.1,
                        evidence_text="text1",
                        source="s1",
                    ),
                ],
            ),
            (
                Constraint(
                    id="c2",
                    type=ConstraintType.LOCATION,
                    description="Constraint 2",
                    value="value2",
                ),
                [
                    ConstraintEvidence(
                        positive_confidence=0.7,
                        negative_confidence=0.1,
                        uncertainty=0.2,
                        evidence_text="text2",
                        source="s2",
                    ),
                ],
            ),
        ]

        # Test each constraint individually
        for constraint, evidence_list in constraints_and_evidence:
            result = engine.should_reject_candidate(
                candidate, constraint, evidence_list
            )
            assert result.should_reject is False

    def test_returns_first_rejection_via_should_reject(self):
        """Should find rejection using should_reject_candidate."""
        engine = RejectionEngine(positive_threshold=0.4)
        candidate = Candidate(name="Test")

        constraints_and_evidence = [
            (
                Constraint(
                    id="c1",
                    type=ConstraintType.PROPERTY,
                    description="Constraint 1",
                    value="value1",
                ),
                [
                    ConstraintEvidence(
                        positive_confidence=0.8,
                        negative_confidence=0.1,
                        uncertainty=0.1,
                        evidence_text="text1",
                        source="s1",
                    ),
                ],
            ),
            (
                Constraint(
                    id="c2",
                    type=ConstraintType.LOCATION,
                    description="Constraint 2",
                    value="value2",
                ),
                [
                    ConstraintEvidence(
                        positive_confidence=0.2,  # Below threshold - fails
                        negative_confidence=0.1,
                        uncertainty=0.7,
                        evidence_text="text2",
                        source="s2",
                    ),
                ],
            ),
        ]

        # Check each and find first rejection
        first_rejection = None
        for constraint, evidence_list in constraints_and_evidence:
            result = engine.should_reject_candidate(
                candidate, constraint, evidence_list
            )
            if result.should_reject:
                first_rejection = result
                break

        assert first_rejection is not None
        assert first_rejection.should_reject is True
        assert first_rejection.constraint_value == "value2"

    def test_iterates_until_rejection(self):
        """Should stop at first rejection when checking constraints sequentially."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")

        constraints = [
            Constraint(
                id=f"c{i}",
                type=ConstraintType.PROPERTY,
                description=f"Constraint {i}",
                value=f"value{i}",
            )
            for i in range(3)
        ]

        # All pass
        rejection_found = False
        for constraint in constraints:
            evidence_list = [
                ConstraintEvidence(
                    positive_confidence=0.5,
                    negative_confidence=0.1,
                    uncertainty=0.4,
                    evidence_text="text",
                    source="s",
                ),
            ]
            result = engine.should_reject_candidate(
                candidate, constraint, evidence_list
            )
            if result.should_reject:
                rejection_found = True
                break

        assert rejection_found is False


class TestThresholdBehavior:
    """Tests for threshold behavior."""

    def test_exactly_at_negative_threshold(self):
        """Should not reject when exactly at negative threshold."""
        engine = RejectionEngine(
            negative_threshold=0.25, positive_threshold=0.4
        )
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.25,  # Exactly at threshold
                uncertainty=0.25,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        # > not >= so exactly at threshold should not reject
        assert result.should_reject is False

    def test_exactly_at_positive_threshold(self):
        """Should not reject when exactly at positive threshold."""
        engine = RejectionEngine(
            negative_threshold=0.25, positive_threshold=0.4
        )
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.4,  # Exactly at threshold
                negative_confidence=0.2,
                uncertainty=0.4,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        # < not <= so exactly at threshold should not reject
        assert result.should_reject is False

    def test_just_above_negative_threshold(self):
        """Should reject when just above negative threshold."""
        engine = RejectionEngine(negative_threshold=0.25)
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.251,  # Just above threshold
                uncertainty=0.249,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.should_reject is True

    def test_just_below_positive_threshold(self):
        """Should reject when just below positive threshold."""
        engine = RejectionEngine(
            negative_threshold=0.25, positive_threshold=0.4
        )
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.399,  # Just below threshold
                negative_confidence=0.1,
                uncertainty=0.501,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.should_reject is True


class TestReasonFormatting:
    """Tests for reason formatting."""

    def test_negative_evidence_percentage_format(self):
        """Should format negative evidence as percentage."""
        engine = RejectionEngine(negative_threshold=0.25)
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.35,
                uncertainty=0.15,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert "35%" in result.reason

    def test_positive_evidence_percentage_format(self):
        """Should format positive evidence as percentage."""
        engine = RejectionEngine(
            negative_threshold=0.25, positive_threshold=0.4
        )
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.25,  # Below threshold
                negative_confidence=0.1,
                uncertainty=0.65,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert "25%" in result.reason


class TestEdgeCases:
    """Tests for edge cases."""

    def test_single_evidence_item(self):
        """Should handle single evidence item."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.7,
                negative_confidence=0.1,
                uncertainty=0.2,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.positive_confidence == 0.7
        assert result.negative_confidence == 0.1

    def test_many_evidence_items(self):
        """Should handle many evidence items."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.5,
                negative_confidence=0.2,
                uncertainty=0.3,
                evidence_text=f"text{i}",
                source=f"s{i}",
            )
            for i in range(100)
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.positive_confidence == 0.5
        assert result.negative_confidence == 0.2

    def test_all_zero_confidence(self):
        """Should handle all zero confidence."""
        engine = RejectionEngine(positive_threshold=0.4)
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.0,
                negative_confidence=0.0,
                uncertainty=1.0,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        # Should reject due to low positive
        assert result.should_reject is True

    def test_all_high_positive(self):
        """Should handle all high positive evidence."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.9,
                negative_confidence=0.05,
                uncertainty=0.05,
                evidence_text="text1",
                source="s1",
            ),
            ConstraintEvidence(
                positive_confidence=0.95,
                negative_confidence=0.03,
                uncertainty=0.02,
                evidence_text="text2",
                source="s2",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.should_reject is False

    def test_all_high_negative(self):
        """Should handle all high negative evidence."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.1,
                negative_confidence=0.8,
                uncertainty=0.1,
                evidence_text="text1",
                source="s1",
            ),
            ConstraintEvidence(
                positive_confidence=0.15,
                negative_confidence=0.75,
                uncertainty=0.1,
                evidence_text="text2",
                source="s2",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        assert result.should_reject is True

    def test_empty_constraint_results(self):
        """Should handle empty constraint results."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")

        constraint_results = {}

        with patch(
            "local_deep_research.advanced_search_system.constraint_checking.rejection_engine.logger"
        ):
            result = engine.check_all_constraints(candidate, constraint_results)

        assert result is None

    def test_constraint_with_no_evidence(self):
        """Should handle constraint with no evidence."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        # Test using should_reject_candidate directly
        result = engine.should_reject_candidate(candidate, constraint, [])

        # Empty evidence = no rejection
        assert result.should_reject is False
        assert result.reason == "No evidence available"


class TestCandidateLogging:
    """Tests for candidate logging.

    Note: Logging is tested via should_reject_candidate results since
    check_all_constraints is the one that logs. We verify the result
    format which would trigger specific log messages.
    """

    def test_rejection_result_contains_info_for_logging(self):
        """Rejection result should contain info needed for logging."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test Candidate")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test constraint",
            value="test_constraint",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.1,
                negative_confidence=0.8,
                uncertainty=0.1,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        # Verify result has all info needed for logging
        assert result.should_reject is True
        assert result.constraint_value == "test_constraint"
        assert "High negative evidence" in result.reason

    def test_acceptance_result_contains_info_for_logging(self):
        """Acceptance result should contain info needed for logging."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test Candidate")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test constraint",
            value="test_constraint",
        )

        evidence_list = [
            ConstraintEvidence(
                positive_confidence=0.8,
                negative_confidence=0.1,
                uncertainty=0.1,
                evidence_text="text",
                source="s1",
            ),
        ]

        result = engine.should_reject_candidate(
            candidate, constraint, evidence_list
        )

        # Verify result has all info needed for logging
        assert result.should_reject is False
        assert result.constraint_value == "test_constraint"
        assert result.reason == "Constraints satisfied"


class TestConfidenceScoreExtraction:
    """Tests for confidence score extraction from evidence."""

    def test_extracts_from_evidence_correctly(self):
        """Should correctly extract confidence from ConstraintEvidence."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")
        constraint = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="Test",
            value="value",
        )

        evidence = ConstraintEvidence(
            positive_confidence=0.65,
            negative_confidence=0.15,
            uncertainty=0.2,
            evidence_text="text",
            source="s1",
        )

        result = engine.should_reject_candidate(
            candidate, constraint, [evidence]
        )

        assert result.positive_confidence == 0.65
        assert result.negative_confidence == 0.15


class TestMultipleConstraints:
    """Tests for handling multiple constraints via sequential should_reject_candidate calls."""

    def test_checks_constraints_in_order(self):
        """Should check constraints in order and find first failure."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")

        # First constraint passes, second fails
        constraints_and_evidence = [
            (
                Constraint(
                    id="c1",
                    type=ConstraintType.PROPERTY,
                    description="C1",
                    value="v1",
                ),
                [
                    ConstraintEvidence(
                        positive_confidence=0.8,
                        negative_confidence=0.1,
                        uncertainty=0.1,
                        evidence_text="text1",
                        source="s1",
                    ),
                ],
            ),
            (
                Constraint(
                    id="c2",
                    type=ConstraintType.LOCATION,
                    description="C2",
                    value="v2",
                ),
                [
                    ConstraintEvidence(
                        positive_confidence=0.1,
                        negative_confidence=0.8,
                        uncertainty=0.1,
                        evidence_text="text2",
                        source="s2",
                    ),
                ],
            ),
        ]

        # Check in order
        first_rejection = None
        for constraint, evidence_list in constraints_and_evidence:
            result = engine.should_reject_candidate(
                candidate, constraint, evidence_list
            )
            if result.should_reject:
                first_rejection = result
                break

        assert first_rejection is not None
        assert first_rejection.constraint_value == "v2"

    def test_stops_on_first_rejection(self):
        """Should stop checking after first rejection."""
        engine = RejectionEngine()
        candidate = Candidate(name="Test")

        constraints = [
            Constraint(
                id=f"c{i}",
                type=ConstraintType.PROPERTY,
                description=f"C{i}",
                value=f"v{i}",
            )
            for i in range(5)
        ]

        # Evidence list - third constraint fails
        evidence_sets = [
            [
                ConstraintEvidence(
                    positive_confidence=0.8,
                    negative_confidence=0.1,
                    uncertainty=0.1,
                    evidence_text="t0",
                    source="s0",
                )
            ],
            [
                ConstraintEvidence(
                    positive_confidence=0.7,
                    negative_confidence=0.1,
                    uncertainty=0.2,
                    evidence_text="t1",
                    source="s1",
                )
            ],
            [
                ConstraintEvidence(
                    positive_confidence=0.1,
                    negative_confidence=0.7,
                    uncertainty=0.2,
                    evidence_text="t2",
                    source="s2",
                )
            ],  # Fails
            [
                ConstraintEvidence(
                    positive_confidence=0.8,
                    negative_confidence=0.1,
                    uncertainty=0.1,
                    evidence_text="t3",
                    source="s3",
                )
            ],
            [
                ConstraintEvidence(
                    positive_confidence=0.9,
                    negative_confidence=0.05,
                    uncertainty=0.05,
                    evidence_text="t4",
                    source="s4",
                )
            ],
        ]

        # Check and count how many were checked
        checked_count = 0
        first_rejection = None
        for constraint, evidence_list in zip(constraints, evidence_sets):
            checked_count += 1
            result = engine.should_reject_candidate(
                candidate, constraint, evidence_list
            )
            if result.should_reject:
                first_rejection = result
                break

        # Should have stopped at constraint 2 (index 2, value v2)
        assert first_rejection is not None
        assert first_rejection.constraint_value == "v2"
        assert checked_count == 3  # Stopped after third constraint
