"""Tests for Stage 4: Fact Aggregation."""

from __future__ import annotations

from datetime import date

import pytest

from reviewiq_pipeline.stages.stage4_aggregate import Stage4Aggregator
from reviewiq_pipeline.validation.validators import validate_stage4_output


class TestStage4Aggregator:
    """Tests for Stage 4 aggregator."""

    def test_get_bucket_range_day(self):
        """Test day bucket range calculation."""
        from reviewiq_pipeline.config import Config

        config = Config()
        aggregator = Stage4Aggregator(config)

        target = date(2026, 1, 20)
        start, end = aggregator._get_bucket_range(target, "day")

        assert start == target
        assert end == target

    def test_get_bucket_range_week(self):
        """Test week bucket range calculation."""
        from reviewiq_pipeline.config import Config

        config = Config()
        aggregator = Stage4Aggregator(config)

        # 2026-01-20 is a Tuesday
        target = date(2026, 1, 20)
        start, end = aggregator._get_bucket_range(target, "week")

        # Week should start on Monday (Jan 19) and end on Sunday (Jan 25)
        assert start == date(2026, 1, 19)
        assert end == date(2026, 1, 25)

    def test_get_bucket_range_month(self):
        """Test month bucket range calculation."""
        from reviewiq_pipeline.config import Config

        config = Config()
        aggregator = Stage4Aggregator(config)

        target = date(2026, 1, 20)
        start, end = aggregator._get_bucket_range(target, "month")

        assert start == date(2026, 1, 1)
        assert end == date(2026, 1, 31)

    def test_compute_strength_score(self):
        """Test strength score calculation."""
        from reviewiq_pipeline.config import Config

        config = Config()
        aggregator = Stage4Aggregator(config)

        spans = [
            {"valence": "V-", "intensity": "I3"},  # 4 * 1.0 = 4
            {"valence": "V-", "intensity": "I2"},  # 2 * 1.0 = 2
            {"valence": "V+", "intensity": "I2"},  # 2 * 1.0 = 2
            {"valence": "V0", "intensity": "I1"},  # 1 * 0.0 = 0
        ]

        score = aggregator._compute_strength_score(spans)
        assert score == 8.0

    def test_compute_trust_weighted_strength(self):
        """Test trust-weighted strength calculation."""
        from reviewiq_pipeline.config import Config

        config = Config()
        aggregator = Stage4Aggregator(config)

        spans = [
            {"valence": "V-", "intensity": "I3", "trust_score": 1.0},  # 4 * 1.0 * 1.0 = 4
            {"valence": "V-", "intensity": "I2", "trust_score": 0.5},  # 2 * 1.0 * 0.5 = 1
        ]

        score = aggregator._compute_trust_weighted_strength(spans)
        assert score == 5.0

    def test_compute_fact_metrics(self):
        """Test fact metrics computation."""
        from reviewiq_pipeline.config import Config

        config = Config()
        aggregator = Stage4Aggregator(config)

        spans = [
            {
                "valence": "V-",
                "intensity": "I3",
                "comparative": "CR-N",
                "trust_score": 0.8,
                "rating": 2,
            },
            {
                "valence": "V+",
                "intensity": "I2",
                "comparative": "CR-B",
                "trust_score": 0.9,
                "rating": 5,
            },
        ]

        fact = aggregator._compute_fact_metrics(
            spans,
            "test-business",
            "test-place",
            "2026-01-20",
            "day",
            "urt_code",
            "J1.01",
            "v5.1",
        )

        assert fact["span_count"] == 2
        assert fact["negative_count"] == 1
        assert fact["positive_count"] == 1
        assert fact["i3_count"] == 1
        assert fact["i2_count"] == 1
        assert fact["cr_better"] == 1
        assert fact["avg_rating"] == 3.5


class TestStage4Validation:
    """Tests for Stage 4 validation."""

    def test_validate_valid_output(self, sample_stage4_output):
        """Test validation of valid Stage 4 output."""
        result = validate_stage4_output(sample_stage4_output)

        assert result["stage"] == "stage4"
        assert result["passed"] is True

    def test_validate_span_less_than_review(self, sample_stage4_output):
        """Test validation catches span_count < review_count."""
        sample_stage4_output["facts_written"][0]["span_count"] = 0
        sample_stage4_output["facts_written"][0]["review_count"] = 1

        result = validate_stage4_output(sample_stage4_output)

        assert result["passed"] is False
        assert any(e["rule"] == "V4.3" for e in result["errors"])

    def test_validate_valence_sum(self, sample_stage4_output):
        """Test validation catches valence sum mismatch."""
        # Set span_count to 5 but valence counts only sum to 1
        sample_stage4_output["facts_written"][0]["span_count"] = 5

        result = validate_stage4_output(sample_stage4_output)

        assert result["passed"] is False
        assert any(e["rule"] == "V4.4" for e in result["errors"])

    def test_validate_intensity_sum(self, sample_stage4_output):
        """Test validation catches intensity sum mismatch."""
        # Set span_count to 5 but intensity counts only sum to 1
        sample_stage4_output["facts_written"][0]["span_count"] = 5
        # Fix valence sum
        sample_stage4_output["facts_written"][0]["negative_count"] = 5

        result = validate_stage4_output(sample_stage4_output)

        assert result["passed"] is False
        assert any(e["rule"] == "V4.5" for e in result["errors"])

    def test_validate_negative_strength(self, sample_stage4_output):
        """Test validation catches negative strength score."""
        sample_stage4_output["facts_written"][0]["strength_score"] = -1.0

        result = validate_stage4_output(sample_stage4_output)

        assert result["passed"] is False
        assert any(e["rule"] == "V4.6" for e in result["errors"])

    def test_validate_invalid_rating(self, sample_stage4_output):
        """Test validation catches invalid average rating."""
        sample_stage4_output["facts_written"][0]["avg_rating"] = 6.0

        result = validate_stage4_output(sample_stage4_output)

        assert result["passed"] is False
        assert any(e["rule"] == "V4.7" for e in result["errors"])

    def test_validate_null_rating_allowed(self, sample_stage4_output):
        """Test that NULL rating is allowed."""
        sample_stage4_output["facts_written"][0]["avg_rating"] = None

        result = validate_stage4_output(sample_stage4_output)

        # Should still pass (NULL is valid)
        # Check no V4.7 errors
        assert not any(e["rule"] == "V4.7" for e in result["errors"])
