"""Tests for PowerPath Pydantic models.

Tests model construction, camelCase alias parsing, and serialization.
"""

from timeback_powerpath import (
    AssignmentResult,
    Attempt,
    BulkResult,
    ExternalTestCreateResponse,
    GetAttemptsResponse,
    LessonPlanCreateResponse,
    PaginationMeta,
    PowerPathTestQuestion,
    ResetPlacementResponse,
    TestAssignment,
    TestAssignmentsListResponse,
)


class TestTestAssignment:
    """Tests for TestAssignment model."""

    def test_from_camel_case(self):
        """TestAssignment should parse from camelCase JSON."""
        data = {
            "sourcedId": "ta-1",
            "studentSourcedId": "student-1",
            "studentEmail": "student@example.com",
            "assignedByUserSourcedId": None,
            "subject": "Math",
            "grade": "3",
            "assignmentStatus": "assigned",
            "testName": "Test 1",
            "assignedAt": "2024-01-01T00:00:00Z",
            "expiresAt": None,
            "completedAt": None,
        }
        ta = TestAssignment.model_validate(data)
        assert ta.sourced_id == "ta-1"
        assert ta.student_sourced_id == "student-1"
        assert ta.assignment_status == "assigned"
        assert ta.test_name == "Test 1"

    def test_snake_case_access(self):
        """TestAssignment should support snake_case attribute access."""
        ta = TestAssignment(
            sourcedId="ta-1",
            studentSourcedId="student-1",
            studentEmail="student@example.com",
            assignedByUserSourcedId=None,
            subject="Math",
            grade="3",
            assignmentStatus="assigned",
        )
        assert ta.sourced_id == "ta-1"
        assert ta.student_sourced_id == "student-1"
        assert ta.student_email == "student@example.com"


class TestTestAssignmentsListResponse:
    """Tests for TestAssignmentsListResponse model."""

    def test_from_api_response(self):
        """Should parse a full list response with pagination metadata."""
        data = {
            "testAssignments": [
                {
                    "sourcedId": "ta-1",
                    "studentSourcedId": "student-1",
                    "studentEmail": "s@e.com",
                    "assignedByUserSourcedId": None,
                    "subject": "Math",
                    "grade": "3",
                    "assignmentStatus": "assigned",
                }
            ],
            "totalCount": 1,
            "pageCount": 1,
            "pageNumber": 1,
            "offset": 0,
            "limit": 100,
        }
        result = TestAssignmentsListResponse.model_validate(data)
        assert len(result.test_assignments) == 1
        assert result.total_count == 1
        assert result.page_count == 1


class TestPaginationMeta:
    """Tests for PaginationMeta model."""

    def test_from_camel_case(self):
        """PaginationMeta should parse camelCase fields."""
        data = {
            "totalCount": 50,
            "pageCount": 5,
            "pageNumber": 1,
            "offset": 0,
            "limit": 10,
        }
        meta = PaginationMeta.model_validate(data)
        assert meta.total_count == 50
        assert meta.page_count == 5
        assert meta.page_number == 1


class TestAssignmentResultModel:
    """Tests for AssignmentResult model."""

    def test_from_camel_case(self):
        """AssignmentResult should parse camelCase JSON."""
        data = {
            "assignmentId": "a-1",
            "lessonId": "l-1",
            "resourceId": "r-1",
        }
        result = AssignmentResult.model_validate(data)
        assert result.assignment_id == "a-1"
        assert result.lesson_id == "l-1"
        assert result.resource_id == "r-1"


class TestAttemptModel:
    """Tests for Attempt model."""

    def test_from_camel_case(self):
        """Attempt should parse camelCase JSON."""
        data = {
            "attempt": 1,
            "score": 85.0,
            "scoreStatus": "fully graded",
            "xp": 10,
            "startedAt": "2024-01-01T00:00:00Z",
            "completedAt": None,
        }
        attempt = Attempt.model_validate(data)
        assert attempt.attempt == 1
        assert attempt.score == 85.0
        assert attempt.score_status == "fully graded"
        assert attempt.xp == 10
        assert attempt.started_at == "2024-01-01T00:00:00Z"
        assert attempt.completed_at is None

    def test_nullable_fields(self):
        """Attempt should handle null attempt number."""
        attempt = Attempt(
            attempt=None,
            score=0,
            scoreStatus="not submitted",
            xp=None,
            startedAt=None,
            completedAt=None,
        )
        assert attempt.attempt is None
        assert attempt.xp is None


class TestExternalTestCreateResponse:
    """Tests for ExternalTestCreateResponse model."""

    def test_from_camel_case(self):
        """ExternalTestCreateResponse should parse camelCase JSON."""
        data = {
            "lessonType": "test-out",
            "lessonId": "l-1",
            "courseComponentId": "cc-1",
            "resourceId": "r-1",
            "toolProvider": "mastery-track",
        }
        result = ExternalTestCreateResponse.model_validate(data)
        assert result.lesson_type == "test-out"
        assert result.lesson_id == "l-1"
        assert result.tool_provider == "mastery-track"


class TestPowerPathTestQuestion:
    """Tests for PowerPathTestQuestion model."""

    def test_from_camel_case(self):
        """PowerPathTestQuestion should parse camelCase JSON."""
        data = {
            "id": "q-1",
            "index": 0,
            "title": "Question 1",
            "url": "https://example.com/q1",
            "difficulty": "medium",
            "humanApproved": True,
            "learningObjectives": ["lo-1", "lo-2"],
        }
        question = PowerPathTestQuestion.model_validate(data)
        assert question.id == "q-1"
        assert question.human_approved is True
        assert question.learning_objectives == ["lo-1", "lo-2"]


class TestBulkResult:
    """Tests for BulkResult model."""

    def test_with_results_and_errors(self):
        """BulkResult should parse results and errors."""
        data = {
            "success": False,
            "results": [
                {"assignmentId": "a-1", "lessonId": "l-1", "resourceId": "r-1"},
            ],
            "errors": [
                {"row": 2, "message": "Invalid grade"},
            ],
        }
        result = BulkResult.model_validate(data)
        assert result.success is False
        assert len(result.results) == 1
        assert len(result.errors) == 1
        assert result.errors[0].row == 2


class TestLessonPlanCreateResponse:
    """Tests for LessonPlanCreateResponse model."""

    def test_from_camel_case(self):
        """LessonPlanCreateResponse should parse camelCase JSON."""
        data = {"lessonPlanId": "lp-1"}
        result = LessonPlanCreateResponse.model_validate(data)
        assert result.lesson_plan_id == "lp-1"


class TestResetPlacementResponse:
    """Tests for ResetPlacementResponse model."""

    def test_from_camel_case(self):
        """ResetPlacementResponse should parse camelCase JSON."""
        data = {
            "success": True,
            "placementResultsDeleted": 3,
            "onboardingReset": True,
        }
        result = ResetPlacementResponse.model_validate(data)
        assert result.success is True
        assert result.placement_results_deleted == 3
        assert result.onboarding_reset is True


class TestGetAttemptsResponse:
    """Tests for GetAttemptsResponse model."""

    def test_from_api_response(self):
        """Should parse a full attempts response."""
        data = {
            "attempts": [
                {
                    "attempt": 1,
                    "score": 80,
                    "scoreStatus": "fully graded",
                    "xp": 10,
                    "startedAt": "2024-01-01T00:00:00Z",
                    "completedAt": "2024-01-01T00:30:00Z",
                },
                {
                    "attempt": 2,
                    "score": 90,
                    "scoreStatus": "submitted",
                    "xp": None,
                    "startedAt": "2024-01-02T00:00:00Z",
                    "completedAt": None,
                },
            ]
        }
        result = GetAttemptsResponse.model_validate(data)
        assert len(result.attempts) == 2
        assert result.attempts[0].score == 80
        assert result.attempts[1].xp is None
