"""
QTI Input Types

Pydantic models for QTI API request inputs.
"""

from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, Field

from timeback_common import NonEmptyString  # noqa: TC001

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

# ═══════════════════════════════════════════════════════════════════════════════
# LIST PARAMS
# ═══════════════════════════════════════════════════════════════════════════════


class ListParams(BaseModel):
    """Common pagination and sorting parameters for list endpoints."""

    page: int | None = None
    limit: int | None = None
    sort: str | None = None
    order: SortOrder | None = None

    model_config = {"populate_by_name": True}


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


class CorrectResponseInput(BaseModel):
    """Correct response value for a response declaration."""

    value: list[str]

    model_config = {"populate_by_name": True}


class ResponseDeclarationInput(BaseModel):
    """Response declaration input."""

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

    model_config = {"populate_by_name": True}


class OutcomeDeclarationInput(BaseModel):
    """Outcome declaration input."""

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

    model_config = {"populate_by_name": True}


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

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

    model_config = {"populate_by_name": True}


class ResponseProcessingInput(BaseModel):
    """Response processing input."""

    template_type: Literal["match_correct", "map_response"] = Field(alias="templateType")
    response_declaration_identifier: NonEmptyString = Field(alias="responseDeclarationIdentifier")
    outcome_identifier: NonEmptyString = Field(alias="outcomeIdentifier")
    correct_response_identifier: NonEmptyString = Field(alias="correctResponseIdentifier")
    incorrect_response_identifier: NonEmptyString = Field(alias="incorrectResponseIdentifier")
    inline_feedback: InlineFeedbackConfigInput | None = Field(default=None, alias="inlineFeedback")

    model_config = {"populate_by_name": True}


class LearningObjectiveSetInput(BaseModel):
    """Learning objective set input."""

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

    model_config = {"populate_by_name": True}


class ItemMetadataInput(BaseModel):
    """Item metadata input."""

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

    model_config = {"populate_by_name": True}


class ModalFeedbackInput(BaseModel):
    """Modal feedback input."""

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

    model_config = {"populate_by_name": True}


class FeedbackInlineInput(BaseModel):
    """Inline feedback input."""

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

    model_config = {"populate_by_name": True}


class FeedbackBlockInput(BaseModel):
    """Block feedback input."""

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

    model_config = {"populate_by_name": True}


class CreateAssessmentItemInput(BaseModel):
    """Input for creating an assessment item."""

    identifier: NonEmptyString
    title: NonEmptyString
    type: AssessmentItemType
    qti_version: str | None = Field(default=None, alias="qtiVersion")
    time_dependent: bool | None = Field(default=None, alias="timeDependent")
    adaptive: bool | None = None
    response_declarations: list[ResponseDeclarationInput] | None = Field(
        default=None, alias="responseDeclarations"
    )
    outcome_declarations: list[OutcomeDeclarationInput] | None = Field(
        default=None, alias="outcomeDeclarations"
    )
    response_processing: ResponseProcessingInput | None = Field(
        default=None, alias="responseProcessing"
    )
    metadata: ItemMetadataInput | None = None
    modal_feedback: list[ModalFeedbackInput] | None = Field(default=None, alias="modalFeedback")
    feedback_inline: list[FeedbackInlineInput] | None = Field(default=None, alias="feedbackInline")
    feedback_block: list[FeedbackBlockInput] | None = Field(default=None, alias="feedbackBlock")

    model_config = {"populate_by_name": True}


class CreateAssessmentItemXmlInput(BaseModel):
    """Input for creating an assessment item from QTI XML."""

    format: Literal["xml"] = "xml"
    xml: NonEmptyString
    metadata: ItemMetadataInput | None = None

    model_config = {"populate_by_name": True}


class CreateAssessmentItemMetadataInput(BaseModel):
    """Input for creating an assessment item from structured metadata (JSON format)."""

    identifier: NonEmptyString
    title: NonEmptyString
    type: AssessmentItemType
    qti_version: str | None = Field(default=None, alias="qtiVersion")
    time_dependent: bool | None = Field(default=None, alias="timeDependent")
    adaptive: bool | None = None
    response_declarations: list[ResponseDeclarationInput] | None = Field(
        default=None, alias="responseDeclarations"
    )
    outcome_declarations: list[OutcomeDeclarationInput] | None = Field(
        default=None, alias="outcomeDeclarations"
    )
    response_processing: ResponseProcessingInput | None = Field(
        default=None, alias="responseProcessing"
    )
    metadata: ItemMetadataInput | None = None
    modal_feedback: list[ModalFeedbackInput] | None = Field(default=None, alias="modalFeedback")
    feedback_inline: list[FeedbackInlineInput] | None = Field(default=None, alias="feedbackInline")
    feedback_block: list[FeedbackBlockInput] | None = Field(default=None, alias="feedbackBlock")

    model_config = {"populate_by_name": True}


class UpdateAssessmentItemInput(BaseModel):
    """Input for updating an assessment item."""

    identifier: NonEmptyString | None = None
    title: NonEmptyString
    type: AssessmentItemType
    qti_version: str | None = Field(default=None, alias="qtiVersion")
    time_dependent: bool | None = Field(default=None, alias="timeDependent")
    adaptive: bool | None = None
    response_declarations: list[ResponseDeclarationInput] | None = Field(
        default=None, alias="responseDeclarations"
    )
    outcome_declarations: list[OutcomeDeclarationInput] | None = Field(
        default=None, alias="outcomeDeclarations"
    )
    response_processing: ResponseProcessingInput | None = Field(
        default=None, alias="responseProcessing"
    )
    metadata: ItemMetadataInput | None = None
    raw_xml: str = Field(alias="rawXml")
    content: dict[str, Any]
    modal_feedback: list[ModalFeedbackInput] | None = Field(default=None, alias="modalFeedback")
    feedback_inline: list[FeedbackInlineInput] | None = Field(default=None, alias="feedbackInline")
    feedback_block: list[FeedbackBlockInput] | None = Field(default=None, alias="feedbackBlock")

    model_config = {"populate_by_name": True}


class ProcessResponseInput(BaseModel):
    """Input for processing an item response.

    The ``identifier`` is supplied as a method parameter and injected into the
    request body automatically — callers only need to provide ``response``.
    """

    response: str | list[str]

    model_config = {"populate_by_name": True}


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


class AssessmentItemRefInput(BaseModel):
    """Input for adding an item reference to a section."""

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

    model_config = {"populate_by_name": True}


class AssessmentSectionInput(BaseModel):
    """Input for creating/updating a section."""

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

    model_config = {"populate_by_name": True}


class TestPartInput(BaseModel):
    """Input for creating/updating a test part."""

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

    model_config = {"populate_by_name": True}


class DefaultValueInput(BaseModel):
    """Default value for a test outcome declaration."""

    value: Any | None = None

    model_config = {"populate_by_name": True}


class TestOutcomeDeclarationInput(BaseModel):
    """Test outcome declaration input."""

    identifier: NonEmptyString
    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: DefaultValueInput | None = Field(default=None, alias="defaultValue")

    model_config = {"populate_by_name": True}


class CreateAssessmentTestInput(BaseModel):
    """Input for creating an assessment test."""

    identifier: NonEmptyString
    title: NonEmptyString
    qti_version: str | None = Field(default=None, alias="qtiVersion")
    tool_name: str | None = Field(default=None, alias="toolName")
    tool_version: str | None = Field(default=None, alias="toolVersion")
    qti_test_part: list[TestPartInput] = Field(alias="qti-test-part")
    qti_outcome_declaration: list[TestOutcomeDeclarationInput] | 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

    model_config = {"populate_by_name": True}


class UpdateAssessmentTestInput(BaseModel):
    """Input for updating an assessment test."""

    identifier: NonEmptyString | None = None
    title: NonEmptyString
    qti_version: str | None = Field(default=None, alias="qtiVersion")
    tool_name: str | None = Field(default=None, alias="toolName")
    tool_version: str | None = Field(default=None, alias="toolVersion")
    qti_test_part: list[TestPartInput] = Field(alias="qti-test-part")
    qti_outcome_declaration: list[TestOutcomeDeclarationInput] | 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

    model_config = {"populate_by_name": True}


class UpdateTestMetadataInput(BaseModel):
    """Input for updating assessment test metadata only."""

    metadata: dict[str, Any] | None = None

    model_config = {"populate_by_name": True}


class ReorderItemsInput(BaseModel):
    """Input for reordering items in a section."""

    items: list[AssessmentItemRefInput] = Field(min_length=1)

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# STIMULUS INPUTS
# ═══════════════════════════════════════════════════════════════════════════════


class StylesheetInput(BaseModel):
    """Stylesheet input."""

    href: NonEmptyString
    type: NonEmptyString

    model_config = {"populate_by_name": True}


class CatalogInfoInput(BaseModel):
    """Catalog info input."""

    id: NonEmptyString
    support: str
    content: str

    model_config = {"populate_by_name": True}


class CreateStimulusInput(BaseModel):
    """Input for creating a stimulus."""

    identifier: NonEmptyString
    title: NonEmptyString
    content: str
    label: str | None = None
    language: str | None = None
    stylesheet: StylesheetInput | None = None
    catalog_info: list[CatalogInfoInput] | None = Field(default=None, 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

    model_config = {"populate_by_name": True}


class UpdateStimulusInput(BaseModel):
    """Input for updating a stimulus."""

    identifier: NonEmptyString | None = None
    title: NonEmptyString
    content: str
    label: str | None = None
    language: str | None = None
    stylesheet: StylesheetInput | None = None
    catalog_info: list[CatalogInfoInput] | None = Field(default=None, 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
    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# VALIDATION INPUTS
# ═══════════════════════════════════════════════════════════════════════════════


class ValidateInput(BaseModel):
    """Input for validating a single QTI XML document."""

    schema_type: ValidationSchema = Field(alias="schema")
    xml: str | None = None
    entity_id: str | None = Field(default=None, alias="entityId")

    model_config = {"populate_by_name": True}


class ValidateBatchInput(BaseModel):
    """Input for batch validating QTI XML documents."""

    schema_type: ValidationSchema = Field(alias="schema")
    xml: list[str]
    entity_ids: list[str] = Field(alias="entityIds")

    model_config = {"populate_by_name": True}


# ═══════════════════════════════════════════════════════════════════════════════
# LESSON INPUTS
# ═══════════════════════════════════════════════════════════════════════════════


class SubmitLessonFeedbackInput(BaseModel):
    """Input for submitting lesson feedback."""

    question_id: str | None = Field(default=None, alias="questionId")
    user_id: NonEmptyString = Field(alias="userId")
    feedback: NonEmptyString
    lesson_id: NonEmptyString = Field(alias="lessonId")
    human_approved: bool | None = Field(default=None, alias="humanApproved")

    model_config = {"populate_by_name": True}


__all__ = [
    "AssessmentItemRefInput",
    "AssessmentSectionInput",
    "CatalogInfoInput",
    "CorrectResponseInput",
    "CreateAssessmentItemInput",
    "CreateAssessmentItemMetadataInput",
    "CreateAssessmentItemXmlInput",
    "CreateAssessmentTestInput",
    "CreateStimulusInput",
    "DefaultValueInput",
    "FeedbackBlockInput",
    "FeedbackInlineInput",
    "InlineFeedbackConfigInput",
    "ItemMetadataInput",
    "LearningObjectiveSetInput",
    "ListParams",
    "ModalFeedbackInput",
    "OutcomeDeclarationInput",
    "ProcessResponseInput",
    "ReorderItemsInput",
    "ResponseDeclarationInput",
    "ResponseProcessingInput",
    "StylesheetInput",
    "SubmitLessonFeedbackInput",
    "TestOutcomeDeclarationInput",
    "TestPartInput",
    "UpdateAssessmentItemInput",
    "UpdateAssessmentTestInput",
    "UpdateStimulusInput",
    "UpdateTestMetadataInput",
    "ValidateBatchInput",
    "ValidateInput",
]
