"""
PowerPath Response Types

Pydantic models for PowerPath API responses, matching the TypeScript SDK.
"""

from __future__ import annotations

from typing import Annotated, Any, Literal

from pydantic import BaseModel, Discriminator, Field, Tag

from .base import (  # noqa: TC001
    ExternalTestCapableLessonType,
    PowerPathLessonType,
    PowerPathQuestionDifficulty,
    QuizLikeLessonType,
    ScoreStatus,
    TestAssignmentStatus,
)

# ═══════════════════════════════════════════════════════════════════════════════
# PAGINATION
# ═══════════════════════════════════════════════════════════════════════════════


class PaginationMeta(BaseModel):
    """Pagination metadata from PowerPath list responses."""

    total_count: int = Field(alias="totalCount")
    page_count: int = Field(alias="pageCount")
    page_number: int = Field(alias="pageNumber")
    offset: int
    limit: int

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# TEST ASSIGNMENTS
# ═══════════════════════════════════════════════════════════════════════════════


class TestAssignment(BaseModel):
    """A single test assignment entity."""

    sourced_id: str = Field(alias="sourcedId")
    student_sourced_id: str = Field(alias="studentSourcedId")
    student_email: str = Field(alias="studentEmail")
    assigned_by_user_sourced_id: str | None = Field(alias="assignedByUserSourcedId")
    subject: str
    grade: str
    assignment_status: TestAssignmentStatus = Field(alias="assignmentStatus")
    test_name: str | None = Field(default=None, alias="testName")
    assigned_at: str | None = Field(default=None, alias="assignedAt")
    expires_at: str | None = Field(default=None, alias="expiresAt")
    completed_at: str | None = Field(default=None, alias="completedAt")
    resource_sourced_id: str | None = Field(default=None, alias="resourceSourcedId")
    component_resource_sourced_id: str | None = Field(
        default=None, alias="componentResourceSourcedId"
    )

    model_config = {"populate_by_name": True}


class TestAssignmentsListResponse(PaginationMeta):
    """List response for test assignments."""

    test_assignments: list[TestAssignment] = Field(alias="testAssignments")


class AssignmentResult(BaseModel):
    """Result from creating a test assignment."""

    assignment_id: str = Field(alias="assignmentId")
    lesson_id: str = Field(alias="lessonId")
    resource_id: str = Field(alias="resourceId")

    model_config = {"populate_by_name": True}


class BulkResultError(BaseModel):
    """Error entry in bulk operation results."""

    row: int
    message: str


class BulkResult(BaseModel):
    """Result from bulk operations."""

    success: bool
    results: list[AssignmentResult]
    errors: list[BulkResultError]


# ═══════════════════════════════════════════════════════════════════════════════
# QUESTIONS
# ═══════════════════════════════════════════════════════════════════════════════


class PowerPathQuestionContent(BaseModel):
    """QTI content associated with a question."""

    type: str | None = None
    raw_xml: str = Field(alias="rawXml")

    model_config = {"populate_by_name": True}


class PowerPathQuestionResult(BaseModel):
    """Result of evaluating a student's response to a question."""

    score: float
    feedback: str | dict[str, Any] = ""
    outcomes: dict[str, Any] | None = None


class PowerPathTestQuestion(BaseModel):
    """A question in a PowerPath test."""

    id: str
    index: int
    title: str
    url: str
    difficulty: PowerPathQuestionDifficulty
    human_approved: bool | None = Field(default=None, alias="humanApproved")
    content: PowerPathQuestionContent | None = None
    response: str | list[str] | None = None
    responses: dict[str, str | list[str]] | None = None
    correct: bool | None = None
    result: PowerPathQuestionResult | None = None
    result_id: str | None = Field(default=None, alias="resultId")
    learning_objectives: list[str] | None = Field(default=None, alias="learningObjectives")

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# ASSESSMENTS
# ═══════════════════════════════════════════════════════════════════════════════


class ExternalTestCreateResponse(BaseModel):
    """Result from creating an external test (test-out or placement)."""

    lesson_type: PowerPathLessonType = Field(alias="lessonType")
    lesson_id: str = Field(alias="lessonId")
    course_component_id: str = Field(alias="courseComponentId")
    resource_id: str = Field(alias="resourceId")
    launch_url: str | None = Field(default=None, alias="launchUrl")
    tool_provider: str = Field(alias="toolProvider")
    vendor_id: str | None = Field(default=None, alias="vendorId")
    course_id_on_fail: str | None = Field(default=None, alias="courseIdOnFail")
    grades: list[int | str] | None = None

    model_config = {"populate_by_name": True}


class InternalTestCreateResponse(BaseModel):
    """Result from creating an internal test (QTI or assessment-bank)."""

    lesson_type: PowerPathLessonType = Field(alias="lessonType")
    test_type: Literal["qti", "assessment-bank"] = Field(alias="testType")
    lesson_id: str = Field(alias="lessonId")
    course_component_id: str = Field(alias="courseComponentId")
    resource_id: str = Field(alias="resourceId")
    child_resource_ids: list[str] | None = Field(default=None, alias="childResourceIds")
    course_id_on_fail: str | None = Field(default=None, alias="courseIdOnFail")
    grades: list[int | str] | None = None

    model_config = {"populate_by_name": True}


class Attempt(BaseModel):
    """A single attempt record."""

    attempt: int | None
    score: float
    score_status: ScoreStatus = Field(alias="scoreStatus")
    xp: float | None
    started_at: str | None = Field(alias="startedAt")
    completed_at: str | None = Field(alias="completedAt")

    model_config = {"populate_by_name": True}


class CreateAttemptResponse(BaseModel):
    """Result from creating a new attempt."""

    attempt: Attempt


class GetAttemptsResponse(BaseModel):
    """Result from getting attempts for a lesson."""

    attempts: list[Attempt]


class ResetAttemptResponse(BaseModel):
    """Result from resetting an attempt."""

    success: bool
    score: float


# ═══════════════════════════════════════════════════════════════════════════════
# ASSESSMENT PROGRESS
# ═══════════════════════════════════════════════════════════════════════════════


class RemainingQuestionsPerDifficulty(BaseModel):
    """Remaining question counts per difficulty level."""

    easy: int
    medium: int
    hard: int


class PowerPath100ProgressResponse(BaseModel):
    """Progress for a PowerPath 100 lesson."""

    lesson_type: Literal["powerpath-100"] = Field(alias="lessonType")
    remaining_questions_per_difficulty: RemainingQuestionsPerDifficulty = Field(
        alias="remainingQuestionsPerDifficulty"
    )
    score: float
    seen_questions: list[PowerPathTestQuestion] = Field(alias="seenQuestions")
    test_result_id: str | None = Field(default=None, alias="testResultId")
    attempt: int
    xp: float | None
    multiplier: float | None
    accuracy: float
    correct_questions: int = Field(alias="correctQuestions")
    total_questions: int = Field(alias="totalQuestions")

    model_config = {"populate_by_name": True}


class StandardProgressResponse(BaseModel):
    """Progress for quiz, test-out, placement, or unit-test lessons."""

    lesson_type: QuizLikeLessonType = Field(alias="lessonType")
    finalized: bool
    score: float | None = None
    questions: list[PowerPathTestQuestion]
    tool_provider: str | None = Field(default=None, alias="toolProvider")
    enrollment_failed: bool | None = Field(default=None, alias="enrollmentFailed")
    test_result_id: str | None = Field(default=None, alias="testResultId")
    attempt: int
    xp: float | None = None
    multiplier: float | None = None
    accuracy: float
    correct_questions: int = Field(alias="correctQuestions")
    total_questions: int = Field(alias="totalQuestions")

    model_config = {"populate_by_name": True}


def _progress_discriminator(v: Any) -> str:
    raw = v.get("lessonType", v.get("lesson_type", "")) if isinstance(v, dict) else ""
    return "pp100" if raw == "powerpath-100" else "standard"


GetAssessmentProgressResponse = Annotated[
    Annotated[PowerPath100ProgressResponse, Tag("pp100")]
    | Annotated[StandardProgressResponse, Tag("standard")],
    Discriminator(_progress_discriminator),
]


# ═══════════════════════════════════════════════════════════════════════════════
# GET NEXT QUESTION
# ═══════════════════════════════════════════════════════════════════════════════


class GetNextQuestionResponse(BaseModel):
    """Result from getting the next question in a PowerPath 100 lesson."""

    score: float
    question: PowerPathTestQuestion


# ═══════════════════════════════════════════════════════════════════════════════
# UPDATE STUDENT QUESTION RESPONSE
# ═══════════════════════════════════════════════════════════════════════════════


class ResponseResultFeedback(BaseModel):
    """Response feedback for a student's answer."""

    identifier: str | None = None
    value: str | None = None


class ResponseResult(BaseModel):
    """Result of processing a student's response."""

    is_correct: bool = Field(alias="isCorrect")
    score: float
    feedback: ResponseResultFeedback | None = None

    model_config = {"populate_by_name": True}


class PowerPath100UpdateResponseResult(BaseModel):
    """Result from updating a student's response in a PowerPath 100 lesson."""

    lesson_type: Literal["powerpath-100"] = Field(alias="lessonType")
    powerpath_score: float = Field(alias="powerpathScore")
    response_result: ResponseResult = Field(alias="responseResult")
    question_result: Any | None = Field(default=None, alias="questionResult")
    test_result: Any | None = Field(default=None, alias="testResult")
    accuracy: float
    correct_questions: int = Field(alias="correctQuestions")
    total_questions: int = Field(alias="totalQuestions")
    xp: float | None
    multiplier: float | None

    model_config = {"populate_by_name": True}


class StandardUpdateResponseResult(BaseModel):
    """Result from updating a student's response in a quiz/test-out/placement/unit-test."""

    lesson_type: QuizLikeLessonType = Field(alias="lessonType")
    question_result: Any | None = Field(default=None, alias="questionResult")

    model_config = {"populate_by_name": True}


def _update_response_discriminator(v: Any) -> str:
    raw = v.get("lessonType", v.get("lesson_type", "")) if isinstance(v, dict) else ""
    return "pp100" if raw == "powerpath-100" else "standard"


UpdateStudentQuestionResponseResult = Annotated[
    Annotated[PowerPath100UpdateResponseResult, Tag("pp100")]
    | Annotated[StandardUpdateResponseResult, Tag("standard")],
    Discriminator(_update_response_discriminator),
]


# ═══════════════════════════════════════════════════════════════════════════════
# FINALIZE ASSESSMENT
# ═══════════════════════════════════════════════════════════════════════════════


class FinalizeAssessmentResponse(BaseModel):
    """Result from finalizing a test assessment."""

    lesson_type: QuizLikeLessonType = Field(alias="lessonType")
    finalized: bool
    attempt: int

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# TEST OUT
# ═══════════════════════════════════════════════════════════════════════════════


class TestOutCredentials(BaseModel):
    """Credentials for accessing an external test."""

    email: str
    password: str


class TestOutResponse(BaseModel):
    """Result from getting the test-out lesson for a student/course."""

    lesson_type: Literal["test-out"] = Field(alias="lessonType")
    lesson_id: str | None = Field(alias="lessonId")
    finalized: bool
    tool_provider: str | None = Field(alias="toolProvider")
    attempt: int | None = None
    credentials: TestOutCredentials | None = None
    assignment_id: str | None = Field(default=None, alias="assignmentId")
    class_id: str | None = Field(default=None, alias="classId")
    test_url: str | None = Field(default=None, alias="testUrl")
    test_id: str | None = Field(default=None, alias="testId")

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# IMPORT EXTERNAL RESULTS
# ═══════════════════════════════════════════════════════════════════════════════


class ImportExternalResultsResponse(BaseModel):
    """Result from importing external test assignment results."""

    lesson_type: ExternalTestCapableLessonType = Field(alias="lessonType")
    lesson_id: str | None = Field(alias="lessonId")
    tool_provider: str | None = Field(alias="toolProvider")
    finalized: bool
    attempt: int
    credentials: TestOutCredentials | None = None
    assignment_id: str | None = Field(default=None, alias="assignmentId")
    class_id: str | None = Field(default=None, alias="classId")
    test_url: str | None = Field(default=None, alias="testUrl")
    test_id: str | None = Field(default=None, alias="testId")

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# MAKE EXTERNAL TEST ASSIGNMENT
# ═══════════════════════════════════════════════════════════════════════════════


class MakeExternalTestAssignmentResponse(BaseModel):
    """Result from assigning an external test to a student."""

    tool_provider: str = Field(alias="toolProvider")
    lesson_type: ExternalTestCapableLessonType = Field(alias="lessonType")
    attempt: int
    credentials: TestOutCredentials | None = None
    assignment_id: str | None = Field(default=None, alias="assignmentId")
    class_id: str | None = Field(default=None, alias="classId")
    test_url: str | None = Field(default=None, alias="testUrl")
    test_id: str | None = Field(default=None, alias="testId")

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# PLACEMENT
# ═══════════════════════════════════════════════════════════════════════════════


class GetAllPlacementTestsResponse(BaseModel):
    """Result from getting all placement tests."""

    placement_tests: list[Any] = Field(alias="placementTests")

    model_config = {"populate_by_name": True}


class GetCurrentLevelResponse(BaseModel):
    """Result from getting current placement level."""

    grade_level: Any | None = Field(default=None, alias="gradeLevel")
    onboarded: bool | None = None
    available_tests: int = Field(alias="availableTests")

    model_config = {"populate_by_name": True}


class GetNextPlacementTestResponse(BaseModel):
    """Result from getting the next placement test."""

    available_tests: int = Field(alias="availableTests")
    lesson: str

    model_config = {"populate_by_name": True}


class GetSubjectProgressResponse(BaseModel):
    """Result from getting subject progress."""

    progress: list[Any]


class ResetPlacementResponse(BaseModel):
    """Result from resetting placement."""

    success: bool
    placement_results_deleted: int = Field(alias="placementResultsDeleted")
    onboarding_reset: bool = Field(alias="onboardingReset")

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# SCREENING
# ═══════════════════════════════════════════════════════════════════════════════


class ScreeningResultsResponse(BaseModel):
    """Result from screening getResults. Shape depends on MAP integration."""

    model_config = {"extra": "allow"}


class ScreeningSessionResponse(BaseModel):
    """Result from screening getSession. Shape depends on MAP integration."""

    model_config = {"extra": "allow"}


class ScreeningResetSessionResponse(BaseModel):
    """Result from resetting a screening session."""

    success: bool | None = None

    model_config = {"extra": "allow"}


class ScreeningAssignTestResponse(BaseModel):
    """Result from assigning a screening test."""

    success: bool | None = None

    model_config = {"extra": "allow"}


# ═══════════════════════════════════════════════════════════════════════════════
# LESSON PLANS
# ═══════════════════════════════════════════════════════════════════════════════


class LessonPlanCreateResponse(BaseModel):
    """Result from creating a lesson plan."""

    lesson_plan_id: str = Field(alias="lessonPlanId")

    model_config = {"populate_by_name": True}


class LessonPlanOperation(BaseModel):
    """A lesson plan operation record."""

    id: str
    type: str
    payload: Any | None = None
    reason: str | None = None
    created_at: str = Field(alias="createdAt")
    sequence_number: int = Field(alias="sequenceNumber")
    created_by: str | None = Field(default=None, alias="createdBy")

    model_config = {"populate_by_name": True}


class LessonPlanOperationsResponse(BaseModel):
    """Response containing lesson plan operations."""

    operations: list[LessonPlanOperation]


class LessonPlanOperationResult(BaseModel):
    """Result from a single lesson plan operation."""

    success: bool
    message: str | None = None
    operation_id: str | None = Field(default=None, alias="operationId")

    model_config = {"populate_by_name": True}


class SyncOperationError(BaseModel):
    """Error detail from a sync operation."""

    message: str


class SyncOperationResult(BaseModel):
    """Result of a single sync operation."""

    success: bool
    errors: list[SyncOperationError] | None = None


class LessonPlanSyncResult(BaseModel):
    """Result from syncing lesson plan operations."""

    success: bool
    message: str | None = None
    operation_count: int = Field(alias="operationCount")
    operation_results: list[SyncOperationResult] = Field(alias="operationResults")

    model_config = {"populate_by_name": True}


class LessonPlanCourseSyncResult(BaseModel):
    """Result from syncing a course."""

    lesson_plans_affected: list[str] = Field(alias="lessonPlansAffected")

    model_config = {"populate_by_name": True}


class LessonPlanResponse(BaseModel):
    """Response containing a lesson plan."""

    lesson_plan: dict[str, Any] = Field(alias="lessonPlan")

    model_config = {"populate_by_name": True}


class CourseProgressResponse(BaseModel):
    """Response containing course progress."""

    line_items: list[dict[str, Any]] = Field(alias="lineItems")

    model_config = {"populate_by_name": True}


class UpdateStudentItemResponseResult(BaseModel):
    """Result from updating student item response."""

    success: bool | None = None

    model_config = {"extra": "allow"}


# ═══════════════════════════════════════════════════════════════════════════════
# SYLLABUS
# ═══════════════════════════════════════════════════════════════════════════════


class SyllabusResponse(BaseModel):
    """Response containing syllabus data."""

    syllabus: Any | None = None


__all__ = [
    "AssignmentResult",
    "Attempt",
    "BulkResult",
    "BulkResultError",
    "CourseProgressResponse",
    "CreateAttemptResponse",
    "ExternalTestCreateResponse",
    "FinalizeAssessmentResponse",
    "GetAllPlacementTestsResponse",
    "GetAssessmentProgressResponse",
    "GetAttemptsResponse",
    "GetCurrentLevelResponse",
    "GetNextPlacementTestResponse",
    "GetNextQuestionResponse",
    "GetSubjectProgressResponse",
    "ImportExternalResultsResponse",
    "InternalTestCreateResponse",
    "LessonPlanCourseSyncResult",
    "LessonPlanCreateResponse",
    "LessonPlanOperation",
    "LessonPlanOperationResult",
    "LessonPlanOperationsResponse",
    "LessonPlanResponse",
    "LessonPlanSyncResult",
    "MakeExternalTestAssignmentResponse",
    "PaginationMeta",
    "PowerPath100ProgressResponse",
    "PowerPath100UpdateResponseResult",
    "PowerPathQuestionContent",
    "PowerPathQuestionResult",
    "PowerPathTestQuestion",
    "RemainingQuestionsPerDifficulty",
    "ResetAttemptResponse",
    "ResetPlacementResponse",
    "ResponseResult",
    "ResponseResultFeedback",
    "ScreeningAssignTestResponse",
    "ScreeningResetSessionResponse",
    "ScreeningResultsResponse",
    "ScreeningSessionResponse",
    "StandardProgressResponse",
    "StandardUpdateResponseResult",
    "SyllabusResponse",
    "SyncOperationError",
    "SyncOperationResult",
    "TestAssignment",
    "TestAssignmentsListResponse",
    "TestOutCredentials",
    "TestOutResponse",
    "UpdateStudentItemResponseResult",
    "UpdateStudentQuestionResponseResult",
]
