"""Tests for CheckResult and ValidationResult classes."""

import json
from datetime import datetime

import pytest

from ai_qa.core.context import Context
from ai_qa.core.result import CheckResult, ValidationResult


class TestCheckResult:
    """Tests for CheckResult."""

    def test_check_result_score_bounds(self) -> None:
        """Test that score outside 0-1 raises error."""
        with pytest.raises(Exception):
            CheckResult(
                name="test",
                passed=True,
                score=1.5,
                threshold=0.5,
                evidence="test",
            )

        with pytest.raises(Exception):
            CheckResult(
                name="test",
                passed=True,
                score=-0.1,
                threshold=0.5,
                evidence="test",
            )

    def test_check_result_threshold_bounds(self) -> None:
        """Test that threshold outside 0-1 raises error."""
        with pytest.raises(Exception):
            CheckResult(
                name="test",
                passed=True,
                score=0.8,
                threshold=1.5,
                evidence="test",
            )

        with pytest.raises(Exception):
            CheckResult(
                name="test",
                passed=True,
                score=0.8,
                threshold=-0.1,
                evidence="test",
            )

    def test_check_result_name_not_empty(self) -> None:
        """Test that empty name raises error."""
        with pytest.raises(Exception):
            CheckResult(
                name="",
                passed=True,
                score=0.8,
                threshold=0.5,
                evidence="test",
            )

    def test_check_result_evidence_not_empty(self) -> None:
        """Test that empty evidence raises error."""
        with pytest.raises(Exception):
            CheckResult(
                name="test",
                passed=True,
                score=0.8,
                threshold=0.5,
                evidence="",
            )

    def test_check_result_latency_non_negative(self) -> None:
        """Test that negative latency raises error."""
        with pytest.raises(Exception):
            CheckResult(
                name="test",
                passed=True,
                score=0.8,
                threshold=0.5,
                evidence="test",
                latency_ms=-1.0,
            )

    def test_check_result_cost_non_negative(self) -> None:
        """Test that negative cost raises error."""
        with pytest.raises(Exception):
            CheckResult(
                name="test",
                passed=True,
                score=0.8,
                threshold=0.5,
                evidence="test",
                cost_usd=-0.01,
            )


class TestValidationResult:
    """Tests for ValidationResult."""

    @pytest.fixture
    def sample_context(self) -> Context:
        """Create a sample context."""
        return Context(output="test output")

    @pytest.fixture
    def passing_check(self) -> CheckResult:
        """Create a passing check result."""
        return CheckResult(
            name="check1",
            passed=True,
            score=0.9,
            threshold=0.5,
            evidence="Passed successfully",
        )

    @pytest.fixture
    def failing_check(self) -> CheckResult:
        """Create a failing check result."""
        return CheckResult(
            name="check2",
            passed=False,
            score=0.3,
            threshold=0.5,
            evidence="Score below threshold",
        )

    def test_validation_result_all_passed(
        self, sample_context: Context, passing_check: CheckResult
    ) -> None:
        """Test passed=True when all checks pass."""
        result = ValidationResult(
            checks=[passing_check],
            context=sample_context,
        )
        assert result.passed is True

    def test_validation_result_one_failed(
        self,
        sample_context: Context,
        passing_check: CheckResult,
        failing_check: CheckResult,
    ) -> None:
        """Test passed=False when any check fails."""
        result = ValidationResult(
            checks=[passing_check, failing_check],
            context=sample_context,
        )
        assert result.passed is False

    def test_validation_result_scores_dict(
        self,
        sample_context: Context,
        passing_check: CheckResult,
        failing_check: CheckResult,
    ) -> None:
        """Test scores property returns correct mapping."""
        result = ValidationResult(
            checks=[passing_check, failing_check],
            context=sample_context,
        )
        scores = result.scores
        assert scores["check1"] == 0.9
        assert scores["check2"] == 0.3

    def test_validation_result_failed_checks(
        self,
        sample_context: Context,
        passing_check: CheckResult,
        failing_check: CheckResult,
    ) -> None:
        """Test failed_checks filters correctly."""
        result = ValidationResult(
            checks=[passing_check, failing_check],
            context=sample_context,
        )
        failed = result.failed_checks
        assert len(failed) == 1
        assert failed[0].name == "check2"

    def test_validation_result_total_cost(
        self, sample_context: Context
    ) -> None:
        """Test total_cost sums correctly."""
        check1 = CheckResult(
            name="check1",
            passed=True,
            score=0.8,
            threshold=0.5,
            evidence="test",
            cost_usd=0.01,
        )
        check2 = CheckResult(
            name="check2",
            passed=True,
            score=0.8,
            threshold=0.5,
            evidence="test",
            cost_usd=0.02,
        )
        result = ValidationResult(
            checks=[check1, check2],
            context=sample_context,
        )
        assert result.total_cost == 0.03

    def test_validation_result_summary(
        self,
        sample_context: Context,
        passing_check: CheckResult,
        failing_check: CheckResult,
    ) -> None:
        """Test summary string is readable."""
        result = ValidationResult(
            checks=[passing_check, failing_check],
            context=sample_context,
        )
        summary = result.summary
        assert "1/2 checks passed" in summary
        assert "check2" in summary

    def test_validation_result_summary_all_passed(
        self, sample_context: Context, passing_check: CheckResult
    ) -> None:
        """Test summary when all passed."""
        result = ValidationResult(
            checks=[passing_check],
            context=sample_context,
        )
        assert result.summary == "1/1 checks passed"

    def test_validation_result_to_dict(
        self, sample_context: Context, passing_check: CheckResult
    ) -> None:
        """Test serialization round-trips."""
        result = ValidationResult(
            checks=[passing_check],
            context=sample_context,
        )
        d = result.to_dict()
        assert "checks" in d
        assert "context" in d
        assert "timestamp" in d
        assert "passed" in d
        assert "scores" in d
        assert "total_cost" in d
        assert "summary" in d

    def test_validation_result_to_json(
        self, sample_context: Context, passing_check: CheckResult
    ) -> None:
        """Test valid JSON output."""
        result = ValidationResult(
            checks=[passing_check],
            context=sample_context,
        )
        json_str = result.to_json()
        parsed = json.loads(json_str)
        assert "checks" in parsed
        assert "context" in parsed

    def test_validation_result_get_check(
        self, sample_context: Context, passing_check: CheckResult
    ) -> None:
        """Test lookup returns correct check."""
        result = ValidationResult(
            checks=[passing_check],
            context=sample_context,
        )
        found = result.get_check("check1")
        assert found is not None
        assert found.name == "check1"

    def test_validation_result_get_check_missing(
        self, sample_context: Context, passing_check: CheckResult
    ) -> None:
        """Test lookup returns None for unknown."""
        result = ValidationResult(
            checks=[passing_check],
            context=sample_context,
        )
        found = result.get_check("unknown")
        assert found is None

    def test_validation_result_assert_passed_ok(
        self, sample_context: Context, passing_check: CheckResult
    ) -> None:
        """Test no error when passed."""
        result = ValidationResult(
            checks=[passing_check],
            context=sample_context,
        )
        result.assert_passed()  # Should not raise

    def test_validation_result_assert_passed_fails(
        self,
        sample_context: Context,
        passing_check: CheckResult,
        failing_check: CheckResult,
    ) -> None:
        """Test raises AssertionError when failed."""
        result = ValidationResult(
            checks=[passing_check, failing_check],
            context=sample_context,
        )
        with pytest.raises(AssertionError):
            result.assert_passed()

    def test_validation_result_timestamp_auto_set(
        self, sample_context: Context, passing_check: CheckResult
    ) -> None:
        """Test that timestamp is auto-set to current time."""
        before = datetime.now()
        result = ValidationResult(
            checks=[passing_check],
            context=sample_context,
        )
        after = datetime.now()
        assert before <= result.timestamp <= after
