# retoor <retoor@molodetz.nl>

from typing import Annotated

from fastapi import APIRouter, Depends, Request
from fastapi.responses import HTMLResponse

from devplacepy.database import get_users_by_uids
from devplacepy.dependencies import json_or_form
from devplacepy.models import QuizQuestionForm, QuizReorderForm
from devplacepy.responses import action_result, respond
from devplacepy.schemas import QuizBuilderOut
from devplacepy.services.audit import record as audit
from devplacepy.services.quiz import QuizError, scoring, store
from devplacepy.utils import require_user

from ._shared import action_error, load_quiz, notify_quiz, quiz_seo, quiz_url, require_editor

router = APIRouter()

KIND_SPECS = [
    {
        "key": kind.key,
        "label": kind.label,
        "icon": kind.icon,
        "has_options": kind.has_options,
        "graded_by": kind.graded_by,
    }
    for kind in scoring.QUESTION_KINDS
]


def _question_payload(data: QuizQuestionForm) -> dict:
    return {
        "kind": data.kind,
        "prompt": data.prompt.strip(),
        "explanation": data.explanation.strip(),
        "points": data.points,
        "media_attachment_uid": data.media_attachment_uid.strip(),
        "correct_boolean": int(bool(data.correct_boolean)),
        "expected_answer": data.expected_answer.strip(),
        "grading_criteria": data.grading_criteria.strip(),
        "numeric_value": data.numeric_value,
        "numeric_tolerance": data.numeric_tolerance,
        "case_sensitive": int(bool(data.case_sensitive)),
        "options": data.option_rows(),
    }


@router.get("/{slug}/edit", response_class=HTMLResponse)
async def quiz_builder(request: Request, slug: str):
    user = require_user(request)
    quiz = require_editor(load_quiz(slug, user), user)
    author = get_users_by_uids([quiz["user_uid"]]).get(quiz["user_uid"])
    seo_ctx = quiz_seo(
        request,
        f"Edit {quiz.get('title') or 'quiz'}",
        "Build and publish your quiz.",
        robots="noindex,follow",
        breadcrumbs=[{"name": quiz.get("title") or "Quiz", "url": quiz_url(quiz)}],
    )
    return respond(
        request,
        "quiz_edit.html",
        {
            **seo_ctx,
            "request": request,
            "user": user,
            "quiz": store.serialize_quiz(quiz, user, author),
            "questions": store.serialize_builder(quiz, user),
            "kinds": KIND_SPECS,
            "validation_errors": store.validation_errors(quiz["uid"]),
            "quiz_error": request.query_params.get("error", ""),
        },
        model=QuizBuilderOut,
    )


@router.post("/{slug}/questions")
async def add_question(
    request: Request,
    slug: str,
    data: Annotated[QuizQuestionForm, Depends(json_or_form(QuizQuestionForm))],
):
    user = require_user(request)
    quiz = require_editor(load_quiz(slug, user), user)
    try:
        question = store.add_question(quiz["uid"], _question_payload(data))
    except QuizError as exc:
        return action_error(request, str(exc), f"/quizzes/{slug}/edit")
    _audit_question(request, user, quiz, question, "create")
    await notify_quiz(quiz["uid"])
    return action_result(
        request,
        f"/quizzes/{slug}/edit",
        data={"uid": question["uid"], "position": question["position"]},
    )


@router.post("/{slug}/questions/reorder")
async def reorder_questions(
    request: Request,
    slug: str,
    data: Annotated[QuizReorderForm, Depends(json_or_form(QuizReorderForm))],
):
    user = require_user(request)
    quiz = require_editor(load_quiz(slug, user), user)
    try:
        store.reorder_questions(quiz["uid"], data.order)
    except QuizError as exc:
        return action_error(request, str(exc), f"/quizzes/{slug}/edit")
    audit.record(
        request,
        "quiz.question.reorder",
        user=user,
        target_type="quiz",
        target_uid=quiz["uid"],
        target_label=quiz.get("title") or quiz["uid"],
        summary=f"{user['username']} reordered the questions of quiz {quiz.get('title')}",
        links=[audit.target("quiz", quiz["uid"], quiz.get("title") or "")],
    )
    await notify_quiz(quiz["uid"])
    return action_result(request, f"/quizzes/{slug}/edit", data={"order": data.order})


@router.post("/{slug}/questions/{question_uid}")
async def edit_question(
    request: Request,
    slug: str,
    question_uid: str,
    data: Annotated[QuizQuestionForm, Depends(json_or_form(QuizQuestionForm))],
):
    user = require_user(request)
    quiz = require_editor(load_quiz(slug, user), user)
    try:
        question = store.edit_question(quiz["uid"], question_uid, _question_payload(data))
    except QuizError as exc:
        return action_error(request, str(exc), f"/quizzes/{slug}/edit")
    _audit_question(request, user, quiz, question, "edit")
    await notify_quiz(quiz["uid"])
    return action_result(request, f"/quizzes/{slug}/edit", data={"uid": question_uid})


@router.post("/{slug}/questions/{question_uid}/delete")
async def delete_question(request: Request, slug: str, question_uid: str):
    user = require_user(request)
    quiz = require_editor(load_quiz(slug, user), user)
    try:
        question = store.delete_question(quiz["uid"], question_uid, user["uid"])
    except QuizError as exc:
        return action_error(request, str(exc), f"/quizzes/{slug}/edit")
    _audit_question(request, user, quiz, question, "delete")
    await notify_quiz(quiz["uid"])
    return action_result(request, f"/quizzes/{slug}/edit", data={"uid": question_uid})


def _audit_question(request, user: dict, quiz: dict, question: dict, action: str) -> None:
    audit.record(
        request,
        f"quiz.question.{action}",
        user=user,
        target_type="quiz",
        target_uid=quiz["uid"],
        target_label=quiz.get("title") or quiz["uid"],
        summary=(
            f"{user['username']} {action}d a {question.get('kind')} question "
            f"on quiz {quiz.get('title')}"
        ),
        metadata={"question_uid": question.get("uid"), "kind": question.get("kind")},
        links=[audit.target("quiz", quiz["uid"], quiz.get("title") or "")],
    )
