"""Unit tests for output validators."""

import pytest

from information_composer.pubmed.analyzer.models import (
    DomainResult,
    SummaryResult,
)
from information_composer.pubmed.analyzer.validators import (
    DomainValidator,
    SummaryValidator,
    ValidationResult,
)


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

    def test_validation_result_defaults(self) -> None:
        """Test ValidationResult with default values."""
        result = ValidationResult(valid=True)
        assert result.valid is True
        assert result.errors == []

    def test_validation_result_with_errors(self) -> None:
        """Test ValidationResult with errors."""
        errors = ["Error 1", "Error 2"]
        result = ValidationResult(valid=False, errors=errors)
        assert result.valid is False
        assert result.errors == errors


class TestSummaryValidator:
    """Tests for SummaryValidator."""

    @pytest.fixture
    def valid_summary(self) -> SummaryResult:
        """Create a valid SummaryResult for testing."""
        return SummaryResult(
            main_findings=["Finding 1", "Finding 2"],
            innovations=["Innovation 1"],
            conclusions="Core conclusions of the study",
        )

    def test_valid_result(self, valid_summary: SummaryResult) -> None:
        """Test that a valid SummaryResult passes validation."""
        validator = SummaryValidator()
        result = validator.validate(valid_summary)

        assert isinstance(result, ValidationResult)
        assert result.valid is True
        assert result.errors == []

    def test_too_many_findings(self, valid_summary: SummaryResult) -> None:
        """Test validation fails when main_findings has >10 items."""
        validator = SummaryValidator()
        valid_summary.main_findings = [f"Finding {i}" for i in range(11)]
        result = validator.validate(valid_summary)

        assert result.valid is False
        assert len(result.errors) == 1
        assert "too many" in result.errors[0].lower() or "10" in result.errors[0]

    def test_empty_conclusions(self, valid_summary: SummaryResult) -> None:
        """Test validation fails when conclusions is empty."""
        validator = SummaryValidator()
        valid_summary.conclusions = ""
        result = validator.validate(valid_summary)

        assert result.valid is False
        assert any("conclusion" in err.lower() for err in result.errors)

    def test_whitespace_conclusions(self, valid_summary: SummaryResult) -> None:
        """Test validation fails when conclusions is only whitespace."""
        validator = SummaryValidator()
        valid_summary.conclusions = "   \n\t  "
        result = validator.validate(valid_summary)

        assert result.valid is False
        assert any("conclusion" in err.lower() for err in result.errors)

    def test_empty_innovations_valid(self, valid_summary: SummaryResult) -> None:
        """Test that empty innovations list is valid (optional field)."""
        validator = SummaryValidator()
        valid_summary.innovations = []
        result = validator.validate(valid_summary)

        assert result.valid is True

    def test_innovations_with_empty_string(self, valid_summary: SummaryResult) -> None:
        """Test validation fails when innovations contains empty string."""
        validator = SummaryValidator()
        valid_summary.innovations = ["Valid innovation", ""]
        result = validator.validate(valid_summary)

        assert result.valid is False
        assert any("innovation" in err.lower() for err in result.errors)


class TestDomainValidator:
    """Tests for DomainValidator."""

    @pytest.fixture
    def valid_domain_result(self) -> DomainResult:
        """Create a valid DomainResult for testing."""
        return DomainResult(
            relevant_domains=["Domain A", "Domain B"],
            domain_scores={"Domain A": 0.9, "Domain B": 0.7},
            primary_domain="Domain A",
            reasoning="Based on the methodology described",
        )

    def test_valid_result(self, valid_domain_result: DomainResult) -> None:
        """Test that a valid DomainResult passes validation."""
        validator = DomainValidator()
        result = validator.validate(valid_domain_result)

        assert isinstance(result, ValidationResult)
        assert result.valid is True
        assert result.errors == []

    def test_primary_not_in_relevant(self, valid_domain_result: DomainResult) -> None:
        """Test validation fails when primary_domain not in relevant_domains."""
        validator = DomainValidator()
        valid_domain_result.primary_domain = "Unknown Domain"
        result = validator.validate(valid_domain_result)

        assert result.valid is False
        assert any(
            "primary" in err.lower() and "relevant" in err.lower()
            for err in result.errors
        )

    def test_score_out_of_range_high(self, valid_domain_result: DomainResult) -> None:
        """Test validation fails when domain_scores contains value > 1."""
        validator = DomainValidator()
        valid_domain_result.domain_scores["Domain A"] = 1.5
        result = validator.validate(valid_domain_result)

        assert result.valid is False
        assert any("0" in err and "1" in err for err in result.errors)

    def test_score_out_of_range_low(self, valid_domain_result: DomainResult) -> None:
        """Test validation fails when domain_scores contains value < 0."""
        validator = DomainValidator()
        valid_domain_result.domain_scores["Domain A"] = -0.5
        result = validator.validate(valid_domain_result)

        assert result.valid is False
        assert any("0" in err and "1" in err for err in result.errors)

    def test_empty_reasoning(self, valid_domain_result: DomainResult) -> None:
        """Test validation fails when reasoning is empty."""
        validator = DomainValidator()
        valid_domain_result.reasoning = ""
        result = validator.validate(valid_domain_result)

        assert result.valid is False
        assert any("reasoning" in err.lower() for err in result.errors)

    def test_whitespace_reasoning(self, valid_domain_result: DomainResult) -> None:
        """Test validation fails when reasoning is only whitespace."""
        validator = DomainValidator()
        valid_domain_result.reasoning = "   \n\t  "
        result = validator.validate(valid_domain_result)

        assert result.valid is False
        assert any("reasoning" in err.lower() for err in result.errors)


class TestValidatorsImport:
    """Tests for module imports."""

    def test_import_validators_module(self) -> None:
        """Test that validators module can be imported."""
        from information_composer.pubmed.analyzer import validators

        assert hasattr(validators, "SummaryValidator")
        assert hasattr(validators, "DomainValidator")
        assert hasattr(validators, "ValidationResult")

    def test_all_exports(self) -> None:
        """Test __all__ exports."""
        from information_composer.pubmed.analyzer.validators import __all__

        assert "SummaryValidator" in __all__
        assert "DomainValidator" in __all__
        assert "ValidationResult" in __all__
