# retoor <retoor@molodetz.nl>

from __future__ import annotations

from ..spec import Action
from ._shared import body, confirm, path, query

KIND_LIST = (
    "single_choice, multiple_choice, true_false, free_text, fill_blank, numeric, "
    "ordering, matching"
)

DOCUMENT_HELP = (
    "The complete quiz as a JSON string: "
    '{"title": "...", "description": "...", '
    '"settings": {"shuffle_questions": true, "reveal_answers": true, '
    '"pass_percent": 70, "time_limit_seconds": 900}, '
    '"questions": [{"kind": "single_choice", "prompt": "...", "points": 1, '
    '"explanation": "...", "options": [{"label": "A"}, {"label": "B", "is_correct": true}]}]}. '
    f"Question kinds: {KIND_LIST}. A free_text question needs expected_answer or "
    "grading_criteria; numeric needs numeric_value; true_false needs correct_boolean; "
    "fill_blank and matching need a match_value on every option."
)


QUIZ_ACTIONS: tuple[Action, ...] = (
    Action(
        name="list_quizzes",
        method="GET",
        path="/quizzes",
        summary="List quizzes with the viewer's per-quiz progress",
        description=(
            "Returns published quizzes plus the signed-in viewer's state per quiz "
            "(todo, in_progress, done) and the cross-quiz scoreboard."
        ),
        handler="http",
        requires_auth=False,
        read_only=True,
        params=(
            query("search", "Match the title, description or author username."),
            query("filter", "One of all, todo, done, mine, drafts. Defaults to all."),
            query("page", "1-based page number."),
        ),
    ),
    Action(
        name="get_quiz",
        method="GET",
        path="/quizzes/{slug}",
        summary="Get one quiz with its stats, leaderboard and comments",
        handler="http",
        requires_auth=False,
        read_only=True,
        params=(path("slug", "Quiz slug or uid."),),
    ),
    Action(
        name="export_quiz",
        method="GET",
        path="/quizzes/{slug}/export",
        summary="Export a quiz as a full JSON document",
        description=(
            "The inverse of import_quiz. The owner's export includes every correct "
            "answer; a public export of a published quiz omits them."
        ),
        handler="http",
        requires_auth=False,
        read_only=True,
        params=(path("slug", "Quiz slug or uid."),),
    ),
    Action(
        name="create_quiz",
        method="POST",
        path="/quizzes/create",
        summary="Create an empty draft quiz",
        handler="http",
        requires_auth=True,
        params=(
            body("title", "Quiz title, 3 to 200 characters.", required=True),
            body("description", "Markdown description."),
            body("shuffle_questions", "Set to 1 to shuffle the question order."),
            body("shuffle_options", "Set to 1 to shuffle the answer options."),
            body("reveal_answers", "Set to 1 to reveal answers after each question."),
            body("allow_review", "Set to 1 to allow reviewing answers on the results screen."),
            body("time_limit_seconds", "Time limit in seconds, 0 for none."),
            body("pass_percent", "Pass mark 0-100, 0 for no verdict."),
        ),
    ),
    Action(
        name="import_quiz",
        method="POST",
        path="/quizzes/import",
        summary="Create a complete quiz from one JSON document",
        description=(
            "The full-automation entry point: creates the draft quiz, every question "
            "and every option in one call. Publish it afterwards with publish_quiz."
        ),
        handler="http",
        requires_auth=True,
        params=(body("document", DOCUMENT_HELP, required=True),),
    ),
    Action(
        name="edit_quiz",
        method="POST",
        path="/quizzes/edit/{slug}",
        summary="Edit a draft quiz's title, description and settings",
        description="Refused with a 400 once the quiz is published.",
        handler="http",
        requires_auth=True,
        params=(
            path("slug", "Quiz slug or uid."),
            body("title", "Quiz title, 3 to 200 characters.", required=True),
            body("description", "Markdown description."),
            body("shuffle_questions", "Set to 1 to shuffle the question order."),
            body("shuffle_options", "Set to 1 to shuffle the answer options."),
            body("reveal_answers", "Set to 1 to reveal answers after each question."),
            body("allow_review", "Set to 1 to allow reviewing answers on the results screen."),
            body("time_limit_seconds", "Time limit in seconds, 0 for none."),
            body("pass_percent", "Pass mark 0-100, 0 for no verdict."),
        ),
    ),
    Action(
        name="publish_quiz",
        method="POST",
        path="/quizzes/{slug}/publish",
        summary="Publish a quiz, freezing it forever",
        description=(
            "IRREVERSIBLE. A published quiz, its questions and its options can never be "
            "edited again; only deletion remains. Refused with the exact list of problems "
            "when the quiz is incomplete."
        ),
        handler="http",
        requires_auth=True,
        params=(path("slug", "Quiz slug or uid."), confirm()),
    ),
    Action(
        name="delete_quiz",
        method="POST",
        path="/quizzes/delete/{slug}",
        summary="Delete a quiz and everything attached to it",
        handler="http",
        requires_auth=True,
        params=(path("slug", "Quiz slug or uid."), confirm()),
    ),
    Action(
        name="add_quiz_question",
        method="POST",
        path="/quizzes/{slug}/questions",
        summary="Add one question to a draft quiz",
        handler="http",
        requires_auth=True,
        params=(
            path("slug", "Quiz slug or uid."),
            body("kind", f"Question kind, one of: {KIND_LIST}.", required=True),
            body("prompt", "The question prompt, markdown.", required=True),
            body("points", "Points for this question, 1 to 100."),
            body("explanation", "Explanation shown after answering."),
            body("options", "Option labels, one per line or comma separated."),
            body("match_values", "Accepted answers aligned with the options, one per line."),
            body("correct_indexes", "Comma separated 0-based indexes of the correct options."),
            body("correct_boolean", "true_false only: 1 when the statement is true."),
            body("expected_answer", "free_text only: the reference answer."),
            body("grading_criteria", "free_text only: criteria for the AI reviewer."),
            body("numeric_value", "numeric only: the correct value."),
            body("numeric_tolerance", "numeric only: the accepted absolute tolerance."),
            body("case_sensitive", "fill_blank only: 1 to compare case sensitively."),
        ),
    ),
    Action(
        name="edit_quiz_question",
        method="POST",
        path="/quizzes/{slug}/questions/{question_uid}",
        summary="Replace one question of a draft quiz",
        handler="http",
        requires_auth=True,
        params=(
            path("slug", "Quiz slug or uid."),
            path("question_uid", "The question uid."),
            body("kind", f"Question kind, one of: {KIND_LIST}.", required=True),
            body("prompt", "The question prompt, markdown.", required=True),
            body("points", "Points for this question, 1 to 100."),
            body("explanation", "Explanation shown after answering."),
            body("options", "Option labels, one per line or comma separated."),
            body("match_values", "Accepted answers aligned with the options, one per line."),
            body("correct_indexes", "Comma separated 0-based indexes of the correct options."),
            body("correct_boolean", "true_false only: 1 when the statement is true."),
            body("expected_answer", "free_text only: the reference answer."),
            body("grading_criteria", "free_text only: criteria for the AI reviewer."),
            body("numeric_value", "numeric only: the correct value."),
            body("numeric_tolerance", "numeric only: the accepted absolute tolerance."),
            body("case_sensitive", "fill_blank only: 1 to compare case sensitively."),
        ),
    ),
    Action(
        name="delete_quiz_question",
        method="POST",
        path="/quizzes/{slug}/questions/{question_uid}/delete",
        summary="Delete one question from a draft quiz",
        handler="http",
        requires_auth=True,
        params=(
            path("slug", "Quiz slug or uid."),
            path("question_uid", "The question uid."),
            confirm(),
        ),
    ),
    Action(
        name="reorder_quiz_questions",
        method="POST",
        path="/quizzes/{slug}/questions/reorder",
        summary="Set the question order of a draft quiz",
        handler="http",
        requires_auth=True,
        params=(
            path("slug", "Quiz slug or uid."),
            body(
                "order",
                "Every question uid in the wanted order, comma separated.",
                required=True,
            ),
        ),
    ),
    Action(
        name="start_quiz_attempt",
        method="POST",
        path="/quizzes/{slug}/attempts",
        summary="Start or resume an attempt on a published quiz",
        description="Always returns the single in-progress attempt for this member.",
        handler="http",
        requires_auth=True,
        params=(path("slug", "Quiz slug or uid."),),
    ),
    Action(
        name="get_quiz_attempt",
        method="GET",
        path="/quizzes/{slug}/attempts/{attempt_uid}",
        summary="Read an attempt with its questions in play order",
        description=(
            "Correct answers are withheld until a question has been answered and the "
            "quiz reveals answers."
        ),
        handler="http",
        requires_auth=True,
        read_only=True,
        params=(
            path("slug", "Quiz slug or uid."),
            path("attempt_uid", "The attempt uid."),
        ),
    ),
    Action(
        name="answer_quiz_question",
        method="POST",
        path="/quizzes/{slug}/attempts/{attempt_uid}/answer",
        summary="Submit one answer and get it graded",
        description=(
            "Each question can be answered exactly once. free_text answers are graded "
            "by the AI reviewer and fall back to keyword overlap when it is unavailable."
        ),
        handler="http",
        requires_auth=True,
        params=(
            path("slug", "Quiz slug or uid."),
            path("attempt_uid", "The attempt uid."),
            body("question_uid", "The question being answered.", required=True),
            body("answer_text", "Free text, the numeric value, or true/false."),
            body("option_uids", "Chosen option uids, comma separated and in order for ordering."),
            body("blanks", "fill_blank only: one answer per blank, comma separated."),
            body("matches", "matching only: the chosen right-hand value per option_uid, in order."),
        ),
    ),
    Action(
        name="finish_quiz_attempt",
        method="POST",
        path="/quizzes/{slug}/attempts/{attempt_uid}/finish",
        summary="Finish an attempt and get the final score",
        handler="http",
        requires_auth=True,
        params=(
            path("slug", "Quiz slug or uid."),
            path("attempt_uid", "The attempt uid."),
        ),
    ),
    Action(
        name="get_quiz_result",
        method="GET",
        path="/quizzes/{slug}/attempts/{attempt_uid}/results",
        summary="Read the result of a finished attempt",
        handler="http",
        requires_auth=True,
        read_only=True,
        params=(
            path("slug", "Quiz slug or uid."),
            path("attempt_uid", "The attempt uid."),
        ),
    ),
    Action(
        name="quiz_leaderboard",
        method="GET",
        path="/quizzes/{slug}/leaderboard",
        summary="Top completed attempts on one quiz",
        handler="http",
        requires_auth=False,
        read_only=True,
        params=(
            path("slug", "Quiz slug or uid."),
            query("limit", "How many entries to return, up to 100."),
        ),
    ),
    Action(
        name="quiz_scoreboard",
        method="GET",
        path="/quizzes/scoreboard",
        summary="The cross-quiz score per user",
        description=(
            "Each member contributes their best completed attempt per quiz, including "
            "quizzes they wrote themselves."
        ),
        handler="http",
        requires_auth=False,
        read_only=True,
        params=(query("limit", "How many entries to return, up to 100."),),
    ),
)
