"""
QTI Response Types

Pydantic models for QTI API responses.
"""

from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, Field

from .base import (  # noqa: TC001
    AssessmentItemType,
    BaseType,
    Cardinality,
    Difficulty,
    FeedbackType,
    Grade,
    NavigationMode,
    ShowHide,
    SortOrder,
    SubmissionMode,
)

TemplateType = Literal["match_correct", "map_response"]

# ═══════════════════════════════════════════════════════════════════════════════
# COMMON STRUCTURES
# ═══════════════════════════════════════════════════════════════════════════════


class CorrectResponse(BaseModel):
    """Correct response value."""

    value: list[str]

    model_config = {"populate_by_name": True}


class ResponseDeclaration(BaseModel):
    """Response declaration for assessment items."""

    identifier: str
    cardinality: Cardinality
    base_type: BaseType | None = Field(default=None, alias="baseType")
    correct_response: CorrectResponse = Field(alias="correctResponse")

    model_config = {"populate_by_name": True}


class OutcomeDeclaration(BaseModel):
    """Outcome declaration for items and tests."""

    identifier: str
    cardinality: Cardinality
    base_type: BaseType | None = Field(default=None, alias="baseType")

    model_config = {"populate_by_name": True}


class DefaultValue(BaseModel):
    """Default value container for outcome declarations."""

    value: Any = None


class TestOutcomeDeclaration(BaseModel):
    """Test outcome declaration with additional properties."""

    identifier: str
    cardinality: Cardinality | None = None
    base_type: BaseType = Field(alias="baseType")
    normal_maximum: float | None = Field(default=None, alias="normalMaximum")
    normal_minimum: float | None = Field(default=None, alias="normalMinimum")
    default_value: DefaultValue | None = Field(default=None, alias="defaultValue")

    model_config = {"populate_by_name": True}


class InlineFeedbackConfig(BaseModel):
    """Inline feedback configuration for response processing."""

    outcome_identifier: str = Field(alias="outcomeIdentifier")
    variable_identifier: str = Field(alias="variableIdentifier")

    model_config = {"populate_by_name": True}


class ResponseProcessing(BaseModel):
    """Response processing configuration."""

    template_type: TemplateType = Field(alias="templateType")
    response_declaration_identifier: str = Field(alias="responseDeclarationIdentifier")
    outcome_identifier: str = Field(alias="outcomeIdentifier")
    correct_response_identifier: str = Field(alias="correctResponseIdentifier")
    incorrect_response_identifier: str = Field(alias="incorrectResponseIdentifier")
    inline_feedback: InlineFeedbackConfig | None = Field(default=None, alias="inlineFeedback")

    model_config = {"populate_by_name": True}


class LearningObjectiveSet(BaseModel):
    """Learning objective set for metadata."""

    source: str
    learning_objective_ids: list[str] = Field(alias="learningObjectiveIds")

    model_config = {"populate_by_name": True}


class ItemMetadata(BaseModel):
    """Item metadata."""

    subject: str | None = None
    grade: Grade | None = None
    difficulty: Difficulty | None = None
    learning_objective_set: list[LearningObjectiveSet] | None = Field(
        default=None, alias="learningObjectiveSet"
    )

    model_config = {"populate_by_name": True}


class ModalFeedback(BaseModel):
    """Modal feedback element."""

    outcome_identifier: str = Field(alias="outcomeIdentifier")
    identifier: str
    show_hide: ShowHide = Field(alias="showHide")
    content: str
    title: str

    model_config = {"populate_by_name": True}


class FeedbackInline(BaseModel):
    """Inline feedback element."""

    outcome_identifier: str = Field(alias="outcomeIdentifier")
    identifier: str
    show_hide: ShowHide = Field(alias="showHide")
    content: str
    class_names: list[str] = Field(alias="class")

    model_config = {"populate_by_name": True}


class FeedbackBlock(BaseModel):
    """Block feedback element."""

    outcome_identifier: str = Field(alias="outcomeIdentifier")
    identifier: str
    show_hide: ShowHide = Field(alias="showHide")
    content: str
    class_names: list[str] = Field(alias="class")

    model_config = {"populate_by_name": True}


class Stylesheet(BaseModel):
    """Stylesheet reference."""

    href: str
    type: str

    model_config = {"populate_by_name": True}


class CatalogInfo(BaseModel):
    """Catalog info entry."""

    id: str
    support: str
    content: str

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# ASSESSMENT ITEM
# ═══════════════════════════════════════════════════════════════════════════════


class AssessmentItem(BaseModel):
    """Assessment item entity."""

    identifier: str
    title: str
    type: AssessmentItemType
    qti_version: str = Field(alias="qtiVersion")
    time_dependent: bool = Field(alias="timeDependent")
    adaptive: bool
    response_declarations: list[ResponseDeclaration] | None = Field(
        default=None, alias="responseDeclarations"
    )
    outcome_declarations: list[OutcomeDeclaration] | None = Field(
        default=None, alias="outcomeDeclarations"
    )
    response_processing: ResponseProcessing | None = Field(default=None, alias="responseProcessing")
    metadata: ItemMetadata | None = None
    raw_xml: str = Field(alias="rawXml")
    content: dict[str, Any]
    modal_feedback: list[ModalFeedback] | None = Field(default=None, alias="modalFeedback")
    feedback_inline: list[FeedbackInline] | None = Field(default=None, alias="feedbackInline")
    feedback_block: list[FeedbackBlock] | None = Field(default=None, alias="feedbackBlock")
    created_at: str = Field(alias="createdAt")
    updated_at: str = Field(alias="updatedAt")
    v: int | None = Field(default=None, alias="__v")

    model_config = {"populate_by_name": True}


class ProcessResponseFeedback(BaseModel):
    """Feedback from processing a response."""

    identifier: str
    value: str

    model_config = {"populate_by_name": True}


class ProcessResponseResult(BaseModel):
    """Result of processing a response."""

    score: float
    feedback: ProcessResponseFeedback | None = None

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# ASSESSMENT TEST
# ═══════════════════════════════════════════════════════════════════════════════


class AssessmentItemRef(BaseModel):
    """Reference to an assessment item within a section."""

    identifier: str
    href: str
    sequence: int | None = None

    model_config = {"populate_by_name": True}


class AssessmentSection(BaseModel):
    """Assessment section within a test part."""

    identifier: str
    title: str
    visible: bool
    required: bool | None = None
    fixed: bool | None = None
    sequence: int
    qti_assessment_item_ref: list[AssessmentItemRef] | None = Field(
        default=None, alias="qti-assessment-item-ref"
    )

    model_config = {"populate_by_name": True}


class TestPart(BaseModel):
    """Test part within an assessment test."""

    identifier: str
    navigation_mode: NavigationMode = Field(alias="navigationMode")
    submission_mode: SubmissionMode = Field(alias="submissionMode")
    qti_assessment_section: list[AssessmentSection] = Field(alias="qti-assessment-section")

    model_config = {"populate_by_name": True}


class AssessmentTest(BaseModel):
    """Assessment test entity."""

    identifier: str
    title: str
    qti_version: str = Field(alias="qtiVersion")
    qti_test_part: list[TestPart] = Field(alias="qti-test-part")
    qti_outcome_declaration: list[TestOutcomeDeclaration] | None = Field(
        default=None, alias="qti-outcome-declaration"
    )
    time_limit: int | None = Field(default=None, alias="timeLimit")
    max_attempts: int | None = Field(default=None, alias="maxAttempts")
    tools_enabled: dict[str, bool] | None = Field(default=None, alias="toolsEnabled")
    metadata: dict[str, Any] | None = None
    raw_xml: str = Field(alias="rawXml")
    content: dict[str, Any]
    created_at: str = Field(alias="createdAt")
    updated_at: str = Field(alias="updatedAt")
    v: int | None = Field(default=None, alias="__v")
    is_valid_xml: bool | None = Field(default=None, alias="isValidXml")

    model_config = {"populate_by_name": True}


class QuestionReference(BaseModel):
    """Question reference within a test."""

    identifier: str
    href: str
    test_part: str = Field(alias="testPart")
    section: str

    model_config = {"populate_by_name": True}


class QuestionWithItem(BaseModel):
    """Question with full item details."""

    reference: QuestionReference
    question: AssessmentItem

    model_config = {"populate_by_name": True}


class QuestionsResponse(BaseModel):
    """Response from GET /assessment-tests/{identifier}/questions."""

    assessment_test: str = Field(alias="assessmentTest")
    title: str
    total_questions: int = Field(alias="totalQuestions")
    questions: list[QuestionWithItem]

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# STIMULUS
# ═══════════════════════════════════════════════════════════════════════════════


class Stimulus(BaseModel):
    """Stimulus entity."""

    identifier: str
    title: str
    label: str | None = None
    language: str | None = None
    stylesheet: Stylesheet | None = None
    catalog_info: list[CatalogInfo] = Field(alias="catalogInfo")
    tool_name: str | None = Field(default=None, alias="toolName")
    tool_version: str | None = Field(default=None, alias="toolVersion")
    metadata: dict[str, Any] | None = None
    raw_xml: str = Field(alias="rawXml")
    content: dict[str, Any]
    created_at: str = Field(alias="createdAt")
    updated_at: str = Field(alias="updatedAt")
    v: int | None = Field(default=None, alias="__v")

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# VALIDATION
# ═══════════════════════════════════════════════════════════════════════════════


class ValidationResult(BaseModel):
    """Single validation result."""

    success: bool
    entity_id: str = Field(alias="entityId")
    xml_content: str | None = Field(default=None, alias="xmlContent")
    validation_errors: list[str] | None = Field(default=None, alias="validationErrors")
    message: str
    error: str | None = None

    model_config = {"populate_by_name": True}


class BatchValidationResult(BaseModel):
    """Batch validation result."""

    results: list[ValidationResult]

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# LESSON FEEDBACK
# ═══════════════════════════════════════════════════════════════════════════════


class LessonFeedback(BaseModel):
    """Lesson feedback entity."""

    question_id: str | None = Field(default=None, alias="questionId")
    user_id: str = Field(alias="userId")
    feedback: str
    type: FeedbackType
    lesson_id: str = Field(alias="lessonId")
    human_approved: bool | list[bool] | None = Field(default=None, alias="humanApproved")

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# API RESPONSES
# ═══════════════════════════════════════════════════════════════════════════════


class ListResponse[T](BaseModel):
    """Paginated list response from QTI API."""

    items: list[T]
    total: int
    page: int
    pages: int
    limit: int
    sort: str
    order: SortOrder

    model_config = {"populate_by_name": True}


class DeleteResponse(BaseModel):
    """Response from DELETE operations."""

    message: str | None = None

    model_config = {"populate_by_name": True}


__all__ = [
    "AssessmentItem",
    "AssessmentItemRef",
    "AssessmentSection",
    "AssessmentTest",
    "BatchValidationResult",
    "CatalogInfo",
    "CorrectResponse",
    "DeleteResponse",
    "FeedbackBlock",
    "FeedbackInline",
    "InlineFeedbackConfig",
    "ItemMetadata",
    "LearningObjectiveSet",
    "LessonFeedback",
    "ListResponse",
    "ModalFeedback",
    "OutcomeDeclaration",
    "ProcessResponseFeedback",
    "ProcessResponseResult",
    "QuestionReference",
    "QuestionWithItem",
    "QuestionsResponse",
    "ResponseDeclaration",
    "ResponseProcessing",
    "Stimulus",
    "Stylesheet",
    "TestOutcomeDeclaration",
    "TestPart",
    "ValidationResult",
]
