"""Recording transport for fixture-driven PowerPath tests."""

from __future__ import annotations

from typing import Any

from test_support.transport_base import BaseRecordingTransport
from test_support.transport_helpers import dump_model
from timeback_common import PowerPathPaths

from ..types.responses import (
    Attempt,
    BulkResult,
    CourseProgressResponse,
    CreateAttemptResponse,
    ExternalTestCreateResponse,
    FinalizeAssessmentResponse,
    GetAllPlacementTestsResponse,
    GetAttemptsResponse,
    GetCurrentLevelResponse,
    GetNextPlacementTestResponse,
    GetNextQuestionResponse,
    GetSubjectProgressResponse,
    ImportExternalResultsResponse,
    InternalTestCreateResponse,
    LessonPlanCourseSyncResult,
    LessonPlanCreateResponse,
    LessonPlanOperation,
    LessonPlanOperationResult,
    LessonPlanOperationsResponse,
    LessonPlanResponse,
    LessonPlanSyncResult,
    MakeExternalTestAssignmentResponse,
    PowerPathTestQuestion,
    ResetAttemptResponse,
    ResetPlacementResponse,
    ScreeningAssignTestResponse,
    ScreeningResetSessionResponse,
    ScreeningResultsResponse,
    ScreeningSessionResponse,
    StandardProgressResponse,
    StandardUpdateResponseResult,
    SyllabusResponse,
    TestOutResponse,
    UpdateStudentItemResponseResult,
)


def create_recording_transport(
    fail_request: dict[str, Any] | None = None,
    transport_config: dict[str, Any] | None = None,
) -> PowerPathRecordingTransport:
    """Create a transport-like object that records calls and returns stub responses."""
    return PowerPathRecordingTransport(
        fail_request=fail_request,
        transport_config=transport_config,
    )


class PowerPathRecordingTransport(BaseRecordingTransport):
    """PowerPath-specific recording transport with resource-scoped stubs."""

    def __init__(self, **kwargs: Any) -> None:
        super().__init__(**kwargs)
        self.paths = PowerPathPaths()
        self._apply_exclude_paths()

    def _default_get_stub(self, path: str) -> dict[str, Any]:
        for resolver in (
            _assignments_get_stub,
            _syllabus_get_stub,
            _screening_get_stub,
            _placement_get_stub,
            _lesson_plans_get_stub,
            _assessment_get_stub,
        ):
            response = resolver(path)
            if response is not None:
                return response
        return {}

    def _default_post_stub(self, path: str) -> dict[str, Any]:
        for resolver in (
            _assignments_post_stub,
            _screening_post_stub,
            _placement_post_stub,
            _lesson_plans_post_stub,
            _assessment_post_stub,
        ):
            response = resolver(path)
            if response is not None:
                return response
        return {}

    def _default_put_stub(self, path: str) -> dict[str, Any]:
        for resolver in (
            _assignments_put_stub,
            _assessment_put_stub,
        ):
            response = resolver(path)
            if response is not None:
                return response
        return {}


def _assessment_standard_progress_stub() -> StandardProgressResponse:
    return StandardProgressResponse.model_validate(
        {
            "lessonType": "quiz",
            "finalized": False,
            "questions": [],
            "toolProvider": "mastery-track",
            "attempt": 1,
            "xp": 0,
            "multiplier": 1,
            "accuracy": 0,
            "correctQuestions": 0,
            "totalQuestions": 0,
        }
    )


def _assessment_external_test_create_stub() -> ExternalTestCreateResponse:
    return ExternalTestCreateResponse.model_validate(
        {
            "lessonType": "test-out",
            "lessonId": "lesson-001",
            "courseComponentId": "component-001",
            "resourceId": "resource-001",
            "toolProvider": "mastery-track",
        }
    )


def _assessment_internal_test_create_stub() -> InternalTestCreateResponse:
    return InternalTestCreateResponse.model_validate(
        {
            "lessonType": "quiz",
            "testType": "qti",
            "lessonId": "lesson-001",
            "courseComponentId": "component-001",
            "resourceId": "resource-001",
        }
    )


def _assessment_test_out_response_stub() -> TestOutResponse:
    return TestOutResponse.model_validate(
        {
            "lessonType": "test-out",
            "lessonId": "lesson-001",
            "finalized": False,
            "toolProvider": "mastery-track",
            "attempt": 1,
        }
    )


def _assessment_import_external_results_stub() -> ImportExternalResultsResponse:
    return ImportExternalResultsResponse.model_validate(
        {
            "lessonType": "test-out",
            "lessonId": "lesson-001",
            "toolProvider": "mastery-track",
            "finalized": True,
            "attempt": 1,
        }
    )


def _assessment_attempt_stub() -> Attempt:
    return Attempt.model_validate(
        {
            "attempt": 1,
            "score": 0,
            "scoreStatus": "not submitted",
            "xp": None,
            "startedAt": None,
            "completedAt": None,
        }
    )


def _assessment_question_stub() -> PowerPathTestQuestion:
    return PowerPathTestQuestion.model_validate(
        {
            "id": "q-001",
            "index": 0,
            "title": "Question",
            "url": "https://example.test/q-001",
            "difficulty": "easy",
        }
    )


def _assessment_get_stub(path: str) -> dict[str, Any] | None:
    if "/getAssessmentProgress" in path:
        return dump_model(_assessment_standard_progress_stub(), exclude_none=False)
    if "/getAttempts" in path:
        return dump_model(
            GetAttemptsResponse(attempts=[_assessment_attempt_stub()]), exclude_none=False
        )
    if "/getNextQuestion" in path:
        return dump_model(
            GetNextQuestionResponse(score=0, question=_assessment_question_stub()),
            exclude_none=False,
        )
    if "/importExternalTestAssignmentResults" in path:
        return dump_model(_assessment_import_external_results_stub(), exclude_none=False)
    if "/testOut" in path:
        return dump_model(_assessment_test_out_response_stub(), exclude_none=False)
    return None


def _assessment_post_stub(path: str) -> dict[str, Any] | None:
    if "/createExternalPlacementTest" in path or "/createExternalTestOut" in path:
        return dump_model(_assessment_external_test_create_stub(), exclude_none=False)
    if "/createInternalTest" in path:
        return dump_model(_assessment_internal_test_create_stub(), exclude_none=False)
    if "/createNewAttempt" in path:
        return dump_model(
            CreateAttemptResponse(attempt=_assessment_attempt_stub()), exclude_none=False
        )
    if "/finalStudentAssessmentResponse" in path:
        return dump_model(
            FinalizeAssessmentResponse.model_validate(
                {"lessonType": "quiz", "finalized": True, "attempt": 1}
            ),
            exclude_none=False,
        )
    if "/makeExternalTestAssignment" in path:
        return dump_model(
            MakeExternalTestAssignmentResponse.model_validate(
                {"toolProvider": "mastery-track", "lessonType": "test-out", "attempt": 1}
            ),
            exclude_none=False,
        )
    if "/resetAttempt" in path:
        return dump_model(ResetAttemptResponse(success=True, score=0), exclude_none=False)
    return None


def _assessment_put_stub(path: str) -> dict[str, Any] | None:
    if "/updateStudentQuestionResponse" in path:
        return dump_model(
            StandardUpdateResponseResult.model_validate({"lessonType": "quiz"}),
            exclude_none=False,
        )
    return None


def _assignments_test_assignment_stub():
    from ..types.responses import AssignmentResult, TestAssignment, TestAssignmentsListResponse

    assignment = TestAssignment.model_validate(
        {
            "sourcedId": "ta-001",
            "studentSourcedId": "student-001",
            "studentEmail": "student@example.com",
            "assignedByUserSourcedId": None,
            "subject": "Math",
            "grade": "5",
            "assignmentStatus": "assigned",
            "testName": "Test 1",
        }
    )
    list_response = TestAssignmentsListResponse.model_validate(
        {
            "testAssignments": [dump_model(assignment, exclude_none=False)],
            "totalCount": 1,
            "pageCount": 1,
            "pageNumber": 1,
            "offset": 0,
            "limit": 100,
        }
    )
    result = AssignmentResult.model_validate(
        {
            "assignmentId": "ta-001",
            "lessonId": "lesson-001",
            "resourceId": "resource-001",
        }
    )
    return assignment, list_response, result


def _assignments_get_stub(path: str) -> dict[str, Any] | None:
    assignment, list_response, _ = _assignments_test_assignment_stub()
    if "/test-assignments/admin" in path or path.endswith("/test-assignments"):
        return dump_model(list_response, exclude_none=False)
    if "/test-assignments/" in path:
        return dump_model(assignment, exclude_none=False)
    return None


def _assignments_post_stub(path: str) -> dict[str, Any] | None:
    _, _, result = _assignments_test_assignment_stub()
    if "/test-assignments/bulk" in path or "/test-assignments/import" in path:
        return dump_model(BulkResult(success=True, results=[result], errors=[]), exclude_none=False)
    if path.endswith("/test-assignments"):
        return dump_model(result, exclude_none=False)
    return None


def _assignments_put_stub(path: str) -> dict[str, Any] | None:
    assignment, _, _ = _assignments_test_assignment_stub()
    if "/test-assignments/" in path:
        return dump_model(assignment, exclude_none=False)
    return None


def _lesson_plan_operation_stub() -> LessonPlanOperation:
    return LessonPlanOperation.model_validate(
        {
            "id": "op-001",
            "type": "set-skipped",
            "payload": None,
            "reason": None,
            "createdAt": "2024-01-01T00:00:00Z",
            "sequenceNumber": 1,
            "createdBy": None,
        }
    )


def _lesson_plans_get_stub(path: str) -> dict[str, Any] | None:
    if "/lessonPlans/getCourseProgress/" in path:
        return dump_model(
            CourseProgressResponse.model_validate({"lineItems": []}), exclude_none=False
        )
    if "/lessonPlans/tree/" in path:
        return dump_model(
            LessonPlanResponse.model_validate({"lessonPlan": {"id": "lesson-plan-001"}}),
            exclude_none=False,
        )
    if "/lessonPlans/" in path and "/operations" in path:
        return dump_model(
            LessonPlanOperationsResponse(operations=[_lesson_plan_operation_stub()]),
            exclude_none=False,
        )
    if "/lessonPlans/" in path:
        return dump_model(
            LessonPlanResponse.model_validate({"lessonPlan": {"id": "lesson-plan-001"}}),
            exclude_none=False,
        )
    return None


def _lesson_plans_post_stub(path: str) -> dict[str, Any] | None:
    if path.endswith("/lessonPlans/"):
        return dump_model(
            LessonPlanCreateResponse.model_validate({"lessonPlanId": "lesson-plan-001"}),
            exclude_none=False,
        )
    if "/lessonPlans/" in path and "/operations/sync" in path:
        return dump_model(
            LessonPlanSyncResult.model_validate(
                {
                    "success": True,
                    "message": "synced",
                    "operationCount": 1,
                    "operationResults": [{"success": True, "errors": []}],
                }
            ),
            exclude_none=False,
        )
    if "/lessonPlans/course/" in path and "/sync" in path:
        return dump_model(
            LessonPlanCourseSyncResult.model_validate({"lessonPlansAffected": ["lesson-plan-001"]}),
            exclude_none=False,
        )
    if "/lessonPlans/" in path and "/recreate" in path:
        return dump_model(
            LessonPlanSyncResult.model_validate(
                {
                    "success": True,
                    "message": "recreated",
                    "operationCount": 1,
                    "operationResults": [{"success": True, "errors": []}],
                }
            ),
            exclude_none=False,
        )
    if "/lessonPlans/" in path and "/operations" in path:
        return dump_model(
            LessonPlanOperationResult.model_validate(
                {"success": True, "message": "created", "operationId": "op-001"}
            ),
            exclude_none=False,
        )
    if "/lessonPlans/updateStudentItemResponse" in path:
        return dump_model(UpdateStudentItemResponseResult(success=True), exclude_none=False)
    return None


def _placement_get_stub(path: str) -> dict[str, Any] | None:
    if "/placement/getAllPlacementTests" in path:
        return dump_model(
            GetAllPlacementTestsResponse.model_validate({"placementTests": []}),
            exclude_none=False,
        )
    if "/placement/getCurrentLevel" in path:
        return dump_model(
            GetCurrentLevelResponse.model_validate(
                {"gradeLevel": "5", "onboarded": True, "availableTests": 1}
            ),
            exclude_none=False,
        )
    if "/placement/getNextPlacementTest" in path:
        return dump_model(
            GetNextPlacementTestResponse.model_validate(
                {"availableTests": 1, "lesson": "lesson-001"}
            ),
            exclude_none=False,
        )
    if "/placement/getSubjectProgress" in path:
        return dump_model(GetSubjectProgressResponse(progress=[]), exclude_none=False)
    if "/placement/" in path:
        return {"student": "student-001", "subject": "Math"}
    return None


def _placement_post_stub(path: str) -> dict[str, Any] | None:
    if "/placement/resetUserPlacement" in path:
        return dump_model(
            ResetPlacementResponse.model_validate(
                {"success": True, "placementResultsDeleted": 1, "onboardingReset": True}
            ),
            exclude_none=False,
        )
    return None


def _screening_get_stub(path: str) -> dict[str, Any] | None:
    if "/screening/results/" in path:
        return dump_model(
            ScreeningResultsResponse.model_validate({"results": []}),
            exclude_none=False,
        )
    if "/screening/session/" in path:
        return dump_model(
            ScreeningSessionResponse.model_validate({"session": {"id": "session-001"}}),
            exclude_none=False,
        )
    return None


def _screening_post_stub(path: str) -> dict[str, Any] | None:
    if "/screening/session/reset" in path:
        return dump_model(ScreeningResetSessionResponse(success=True), exclude_none=False)
    if "/screening/tests/assign" in path:
        return dump_model(ScreeningAssignTestResponse(success=True), exclude_none=False)
    return None


def _syllabus_get_stub(path: str) -> dict[str, Any] | None:
    if "/syllabus/" in path:
        return dump_model(
            SyllabusResponse(syllabus={"courseSourcedId": "course-001"}),
            exclude_none=False,
        )
    return None


__all__ = ["PowerPathRecordingTransport", "create_recording_transport"]
