"""
Unit tests for the conflict-detection logic in app/services/aggregator.py.

This logic flags when models disagree with each other — it is what
makes the LLM's "Risk explanation" section honest instead of papering
over genuine uncertainty. Tested in isolation here since it's pure
function logic with no I/O.
"""

from app.services.aggregator import _detect_conflicts


class TestDetectConflicts:
    def test_no_conflicts_when_all_models_agree(self):
        climate = {"anomaly_label": "normal"}
        feasibility = {"label": "suitable"}
        yield_pred = {"expected_yield_ton_ha": 4.0, "degraded": False}
        trend = {"trend": "stable"}

        conflicts = _detect_conflicts(climate, feasibility, yield_pred, trend)

        assert conflicts == []

    def test_flags_high_anomaly_with_suitable_feasibility(self):
        climate = {"anomaly_label": "high"}
        feasibility = {"label": "suitable"}
        yield_pred = {"expected_yield_ton_ha": 4.0, "degraded": False}
        trend = {"trend": "stable"}

        conflicts = _detect_conflicts(climate, feasibility, yield_pred, trend)

        assert len(conflicts) == 1
        assert "anomaly" in conflicts[0].lower()

    def test_flags_low_yield_with_suitable_feasibility(self):
        climate = {"anomaly_label": "normal"}
        feasibility = {"label": "suitable"}
        yield_pred = {"expected_yield_ton_ha": 0.5, "degraded": False}
        trend = {"trend": "stable"}

        conflicts = _detect_conflicts(climate, feasibility, yield_pred, trend)

        assert any("yield" in c.lower() for c in conflicts)

    def test_does_not_flag_low_yield_when_degraded(self):
        """A degraded (failed) yield model returning 0.0 should not be
        mistaken for a genuine low-yield conflict signal."""
        climate = {"anomaly_label": "normal"}
        feasibility = {"label": "suitable"}
        yield_pred = {"expected_yield_ton_ha": 0.0, "degraded": True}
        trend = {"trend": "stable"}

        conflicts = _detect_conflicts(climate, feasibility, yield_pred, trend)

        assert not any("yield" in c.lower() for c in conflicts)

    def test_flags_downward_trend_with_suitable_feasibility(self):
        climate = {"anomaly_label": "normal"}
        feasibility = {"label": "suitable"}
        yield_pred = {"expected_yield_ton_ha": 4.0, "degraded": False}
        trend = {"trend": "downward"}

        conflicts = _detect_conflicts(climate, feasibility, yield_pred, trend)

        assert any("trend" in c.lower() for c in conflicts)

    def test_can_return_multiple_conflicts_simultaneously(self):
        climate = {"anomaly_label": "high"}
        feasibility = {"label": "suitable"}
        yield_pred = {"expected_yield_ton_ha": 0.5, "degraded": False}
        trend = {"trend": "downward"}

        conflicts = _detect_conflicts(climate, feasibility, yield_pred, trend)

        assert len(conflicts) == 3

    def test_no_conflict_when_feasibility_is_not_suitable(self):
        """Conflicts are specifically about contradicting a 'suitable'
        label — a 'risky' or 'not_suitable' label being paired with bad
        signals is consistent, not contradictory, and should not flag."""
        climate = {"anomaly_label": "high"}
        feasibility = {"label": "risky"}
        yield_pred = {"expected_yield_ton_ha": 0.5, "degraded": False}
        trend = {"trend": "downward"}

        conflicts = _detect_conflicts(climate, feasibility, yield_pred, trend)

        assert conflicts == []
