"""Tests for BaseCheck class."""

import pytest

from ai_qa.core.check import BaseCheck
from ai_qa.core.context import Context
from ai_qa.core.result import CheckResult
from ai_qa.exceptions import ContextValidationError


class ConcreteCheck(BaseCheck):
    """Concrete implementation for testing."""

    name = "test_check"
    version = "1.0.0"

    def evaluate(self, ctx: Context) -> CheckResult:
        """Simple evaluation logic."""
        return CheckResult(
            name=self.name,
            passed=True,
            score=0.8,
            threshold=self.threshold,
            evidence="Test passed",
        )


class ExceptionThrowingCheck(BaseCheck):
    """Check that raises an exception."""

    name = "exception_check"

    def evaluate(self, ctx: Context) -> CheckResult:
        """Raise an exception."""
        raise ValueError("Test exception")


class BadReturnTypeCheck(BaseCheck):
    """Check that returns wrong type."""

    name = "bad_return"

    def evaluate(self, ctx: Context) -> CheckResult:
        """Return wrong type."""
        return {"score": 0.5}  # type: ignore


class ContextValidatingCheck(BaseCheck):
    """Check that validates context."""

    name = "context_check"

    def evaluate(self, ctx: Context) -> CheckResult:
        """Evaluate."""
        return CheckResult(
            name=self.name,
            passed=True,
            score=0.8,
            threshold=self.threshold,
            evidence="OK",
        )

    def validate_context(self, ctx: Context) -> None:
        """Require ground_truth."""
        if ctx.ground_truth is None:
            raise ContextValidationError(
                "ContextValidatingCheck requires ground_truth"
            )


def test_base_check_is_abstract() -> None:
    """Test that can't instantiate directly."""
    with pytest.raises(TypeError):
        BaseCheck(threshold=0.5)  # type: ignore


def test_check_threshold_validation() -> None:
    """Test that threshold outside 0-1 raises error."""
    with pytest.raises(ValueError):
        ConcreteCheck(threshold=1.5)

    with pytest.raises(ValueError):
        ConcreteCheck(threshold=-0.1)


def test_check_threshold_valid() -> None:
    """Test that valid thresholds work."""
    check = ConcreteCheck(threshold=0.0)
    assert check.threshold == 0.0

    check = ConcreteCheck(threshold=1.0)
    assert check.threshold == 1.0

    check = ConcreteCheck(threshold=0.5)
    assert check.threshold == 0.5


def test_check_run_wraps_timing() -> None:
    """Test that latency_ms is set after run."""
    check = ConcreteCheck()
    ctx = Context(output="test")
    result = check.run(ctx)
    assert result.latency_ms > 0.0


def test_check_run_catches_exceptions() -> None:
    """Test that exception returns failed result, not crash."""
    check = ExceptionThrowingCheck()
    ctx = Context(output="test")
    result = check.run(ctx)
    assert result.passed is False
    assert result.score == 0.0
    assert "ValueError" in result.evidence


def test_check_run_validates_return_type() -> None:
    """Test that evaluate() must return CheckResult."""
    check = BadReturnTypeCheck()
    ctx = Context(output="test")
    result = check.run(ctx)
    assert result.passed is False
    assert "CheckResult" in result.evidence


def test_check_run_sets_version() -> None:
    """Test that run() sets check_version."""
    check = ConcreteCheck()
    ctx = Context(output="test")
    result = check.run(ctx)
    assert result.check_version == "1.0.0"


def test_check_validate_context_default() -> None:
    """Test that base implementation is no-op."""
    check = ConcreteCheck()
    ctx = Context(output="test")
    check.validate_context(ctx)  # Should not raise


def test_check_validate_context_custom() -> None:
    """Test that custom validation works."""
    check = ContextValidatingCheck()

    # Should work with ground_truth
    ctx = Context(output="test", ground_truth="expected")
    check.validate_context(ctx)  # Should not raise

    # Should fail without ground_truth
    ctx_bad = Context(output="test")
    with pytest.raises(ContextValidationError):
        check.validate_context(ctx_bad)


def test_check_stores_config() -> None:
    """Test that config kwargs are stored."""
    check = ConcreteCheck(threshold=0.7, custom_param="value")
    assert check.threshold == 0.7
    assert check.config["custom_param"] == "value"


def test_check_name_and_version() -> None:
    """Test that name and version are set."""
    check = ConcreteCheck()
    assert check.name == "test_check"
    assert check.version == "1.0.0"


def test_check_run_preserves_evaluate_result() -> None:
    """Test that run() doesn't modify the core result."""
    check = ConcreteCheck()
    ctx = Context(output="test")
    result = check.run(ctx)
    assert result.name == "test_check"
    assert result.passed is True
    assert result.score == 0.8
    assert result.evidence == "Test passed"
