"""Tests for comment Pydantic schemas."""

from datetime import datetime

import pytest
from pydantic import ValidationError

from preloop.schemas.comment import (
    CommentBase,
    CommentCreate,
    CommentList,
    CommentResponse,
    CommentSearchResults,
)


class TestCommentBase:
    """Test CommentBase schema."""

    def test_create_with_required_fields(self):
        """Test creating CommentBase with required fields only."""
        comment = CommentBase(body="This is a test comment")

        assert comment.body == "This is a test comment"
        assert comment.meta_data is None

    def test_create_with_all_fields(self):
        """Test creating CommentBase with all fields."""
        metadata = {"author_id": "user123", "is_internal": True}
        comment = CommentBase(body="Test comment with metadata", meta_data=metadata)

        assert comment.body == "Test comment with metadata"
        assert comment.meta_data == metadata

    def test_body_required(self):
        """Test that body field is required."""
        with pytest.raises(ValidationError) as exc_info:
            CommentBase()

        errors = exc_info.value.errors()
        assert any(error["loc"][0] == "body" for error in errors)


class TestCommentCreate:
    """Test CommentCreate schema."""

    def test_inherits_from_base(self):
        """Test that CommentCreate inherits from CommentBase."""
        comment = CommentCreate(body="Creating a new comment")

        assert isinstance(comment, CommentBase)
        assert comment.body == "Creating a new comment"

    def test_create_with_metadata(self):
        """Test creating with metadata."""
        metadata = {"priority": "high", "tags": ["bug", "urgent"]}
        comment = CommentCreate(body="Bug report comment", meta_data=metadata)

        assert comment.body == "Bug report comment"
        assert comment.meta_data == metadata


class TestCommentResponse:
    """Test CommentResponse schema."""

    def test_create_with_required_fields(self):
        """Test creating CommentResponse with required fields."""
        comment = CommentResponse(
            id="comment-123",
            issue_id="issue-456",
            body="Response comment",
            created_at="2025-01-15T10:00:00Z",
        )

        assert comment.id == "comment-123"
        assert comment.issue_id == "issue-456"
        assert comment.body == "Response comment"
        assert comment.created_at == "2025-01-15T10:00:00Z"
        assert comment.author is None
        assert comment.updated_at is None
        assert comment.score is None

    def test_create_with_all_fields(self):
        """Test creating CommentResponse with all fields."""
        metadata = {"source": "webhook"}
        comment = CommentResponse(
            id="comment-789",
            issue_id="issue-101",
            body="Full comment response",
            author="john_doe",
            created_at="2025-01-15T10:00:00Z",
            updated_at="2025-01-15T11:00:00Z",
            meta_data=metadata,
            score=0.95,
        )

        assert comment.id == "comment-789"
        assert comment.issue_id == "issue-101"
        assert comment.body == "Full comment response"
        assert comment.author == "john_doe"
        assert comment.created_at == "2025-01-15T10:00:00Z"
        assert comment.updated_at == "2025-01-15T11:00:00Z"
        assert comment.meta_data == metadata
        assert comment.score == 0.95

    def test_datetime_field_validator_with_datetime_object(self):
        """Test datetime validator converts datetime to ISO string."""
        now = datetime.now()
        comment = CommentResponse(
            id="comment-123",
            issue_id="issue-456",
            body="Test",
            created_at=now,
            updated_at=now,
        )

        assert comment.created_at == now.isoformat()
        assert comment.updated_at == now.isoformat()

    def test_datetime_field_validator_with_string(self):
        """Test datetime validator accepts string."""
        iso_string = "2025-01-15T10:00:00Z"
        comment = CommentResponse(
            id="comment-123",
            issue_id="issue-456",
            body="Test",
            created_at=iso_string,
            updated_at=iso_string,
        )

        assert comment.created_at == iso_string
        assert comment.updated_at == iso_string

    def test_datetime_field_validator_with_none(self):
        """Test datetime validator handles None for optional fields."""
        comment = CommentResponse(
            id="comment-123",
            issue_id="issue-456",
            body="Test",
            created_at="2025-01-15T10:00:00Z",
            updated_at=None,
        )

        assert comment.updated_at is None

    def test_datetime_field_validator_rejects_invalid_type(self):
        """Test datetime validator rejects invalid types."""
        with pytest.raises((ValidationError, TypeError)) as exc_info:
            CommentResponse(
                id="comment-123",
                issue_id="issue-456",
                body="Test",
                created_at=12345,  # Invalid: integer
            )

        # Validator raises TypeError for invalid types
        if isinstance(exc_info.value, TypeError):
            assert "must be a datetime object or a string" in str(exc_info.value)
        else:
            # Or Pydantic ValidationError
            errors = exc_info.value.errors()
            assert len(errors) > 0

    def test_from_attributes_config(self):
        """Test that from_attributes is enabled."""
        assert CommentResponse.model_config.get("from_attributes") is True


class TestCommentList:
    """Test CommentList schema."""

    def test_create_comment_list(self):
        """Test creating CommentList with pagination."""
        items = [
            CommentResponse(
                id="comment-1",
                issue_id="issue-1",
                body="First comment",
                created_at="2025-01-15T10:00:00Z",
            ),
            CommentResponse(
                id="comment-2",
                issue_id="issue-1",
                body="Second comment",
                created_at="2025-01-15T11:00:00Z",
            ),
        ]

        comment_list = CommentList(items=items, total=10, limit=2, offset=0)

        assert len(comment_list.items) == 2
        assert comment_list.total == 10
        assert comment_list.limit == 2
        assert comment_list.offset == 0

    def test_empty_comment_list(self):
        """Test creating empty CommentList."""
        comment_list = CommentList(items=[], total=0, limit=10, offset=0)

        assert len(comment_list.items) == 0
        assert comment_list.total == 0


class TestCommentSearchResults:
    """Test CommentSearchResults schema."""

    def test_create_search_results(self):
        """Test creating CommentSearchResults."""
        items = [
            CommentResponse(
                id="comment-1",
                issue_id="issue-1",
                body="Bug found in login",
                created_at="2025-01-15T10:00:00Z",
                score=0.95,
            ),
            CommentResponse(
                id="comment-2",
                issue_id="issue-2",
                body="Login bug fixed",
                created_at="2025-01-15T11:00:00Z",
                score=0.87,
            ),
        ]

        results = CommentSearchResults(items=items, total=2, query="login bug")

        assert len(results.items) == 2
        assert results.total == 2
        assert results.query == "login bug"
        assert results.items[0].score == 0.95
        assert results.items[1].score == 0.87

    def test_empty_search_results(self):
        """Test creating empty search results."""
        results = CommentSearchResults(items=[], total=0, query="nonexistent")

        assert len(results.items) == 0
        assert results.total == 0
        assert results.query == "nonexistent"

    def test_required_fields(self):
        """Test that all fields are required."""
        with pytest.raises(ValidationError) as exc_info:
            CommentSearchResults()

        errors = exc_info.value.errors()
        error_fields = {error["loc"][0] for error in errors}

        required_fields = {"items", "total", "query"}
        assert required_fields == error_fields
