import csv
import logging
import threading
from typing import List, Literal, Optional
from urllib.parse import quote
from uuid import UUID
from django.http import HttpResponse
from ninja import Router, Query
from ninja.errors import HttpError
from ninja.pagination import paginate
from django.shortcuts import get_object_or_404
from django.contrib.auth.decorators import login_required
from django.db.models import (
    Avg,
    Count,
    Exists,
    F,
    IntegerField,
    Max,
    OuterRef,
    Q,
    Subquery,
)
from django.utils import timezone
from account.decorators import admin_required, super_required
from prompt.models import Conversation, Message
from prompt.utils import get_active_conversation, get_preceding_user_message
from .classifier import classify_message


from .schemas import (
    AwardItemIn,
    AwardItemManageOut,
    AwardItemUpdateIn,
    AwardManageIn,
    AwardManageOut,
    FlagIn,
    FlagStats,
    AwardOut,
    GradebookOut,
    PromptRoundOut,
    ShowcaseDetailOut,
    ShowcaseItemOut,
    ShowcaseSubmissionLookupOut,
    SubmissionCountBucket,
    SubmissionFilter,
    SubmissionIn,
    SubmissionOut,
    RatingScoreIn,
    RandomRatingOut,
    TaskStatsOut,
    TopViewedItem,
    UserTag,
)


from .models import Award, ItemOrdering, Rating, Submission, SubmissionAward
from .gradebook import GradebookFilters, build_gradebook, gradebook_csv_rows
from task.models import Task
from account.models import RoleChoices, User

router = Router()
logger = logging.getLogger(__name__)


def _validate_item_ordering(value: str):
    if value not in ItemOrdering.values:
        raise HttpError(400, "无效的作品排序方式")


def _award_manage_out(award: Award):
    return {
        "id": award.id,
        "name": award.name,
        "description": award.description,
        "sort_order": award.sort_order,
        "is_active": award.is_active,
        "item_ordering": award.item_ordering,
        "item_count": getattr(award, "item_count", None)
        if getattr(award, "item_count", None) is not None
        else award.submission_awards.count(),
    }


def _award_item_ordering(award: Award):
    ordering_map = {
        ItemOrdering.MANUAL: ("sort_order", "id"),
        ItemOrdering.AWARDED_AT: ("-awarded_at", "sort_order", "id"),
        ItemOrdering.SCORE: ("-submission__score", "sort_order", "id"),
        ItemOrdering.VIEW_COUNT: ("-submission__view_count", "sort_order", "id"),
    }
    return ordering_map.get(award.item_ordering, ("sort_order", "id"))


def _award_item_manage_out(item: SubmissionAward):
    has_prompt_chain = getattr(item, "has_prompt_chain", None)
    if has_prompt_chain is None:
        has_prompt_chain = Message.objects.filter(
            submission_id=item.submission_id
        ).exists()
    return {
        "id": item.id,
        "submission_id": item.submission_id,
        "username": item.submission.user.username,
        "task_title": item.submission.task.title,
        "task_display": item.submission.task.display,
        "score": item.submission.score,
        "view_count": item.submission.view_count,
        "sort_order": item.sort_order,
        "awarded_at": item.awarded_at,
        "has_prompt_chain": has_prompt_chain,
        "is_stale": item.is_stale,
    }


def _showcase_submission_lookup_out(submission: Submission):
    return {
        "submission_id": submission.id,
        "username": submission.user.username,
        "task_title": submission.task.title,
        "task_display": submission.task.display,
        "score": submission.score,
        "view_count": submission.view_count,
        "has_prompt_chain": Message.objects.filter(submission=submission).exists(),
    }


@router.post("/")
@login_required
def create_submission(request, payload: SubmissionIn):
    """
    创建一个新的提交
    """
    task = get_object_or_404(Task, id=payload.task_id)

    manual_asst_msg = None
    linked_msg = None
    new_user_msg_id = None

    if payload.prompt:
        conversation = get_active_conversation(request.user, task.id)
        if not conversation:
            conversation = Conversation.objects.create(
                user=request.user, task=task, is_active=False
            )
        user_msg = Message.objects.create(
            conversation=conversation, role="user", content=payload.prompt, source="manual"
        )
        new_user_msg_id = user_msg.id
        manual_asst_msg = Message.objects.create(
            conversation=conversation,
            role="assistant",
            content="",
            code_html=payload.html,
            code_css=payload.css,
            code_js=payload.js,
            source="manual",
        )
    elif payload.message_id:
        linked_msg = Message.objects.filter(
            id=payload.message_id,
            role="assistant",
            conversation__user=request.user,
            conversation__task=task,
        ).first()
        if linked_msg is None:
            logger.warning(
                "create_submission: message_id %s not found for user %s task %s",
                payload.message_id, request.user.id, task.id,
            )
        else:
            user_msg = get_preceding_user_message(linked_msg)
            if user_msg:
                new_user_msg_id = user_msg.id

    # Idempotent: re-submitting the same AI message updates its existing submission
    # instead of creating an orphaned duplicate.
    if linked_msg and linked_msg.submission_id:
        submission = linked_msg.submission
        submission.html = payload.html
        submission.css = payload.css
        submission.js = payload.js
        submission.save(update_fields=["html", "css", "js"])
    else:
        submission = Submission.objects.create(
            user=request.user,
            task=task,
            html=payload.html,
            css=payload.css,
            js=payload.js,
        )

        # Link assistant message to submission
        if manual_asst_msg:
            manual_asst_msg.submission = submission
            manual_asst_msg.save(update_fields=["submission"])
        elif linked_msg:
            linked_msg.submission = submission
            linked_msg.save(update_fields=["submission"])

        # Mark any showcased older submissions from same user+task as stale
        SubmissionAward.objects.filter(
            submission__user=request.user,
            submission__task=task,
            is_stale=False,
        ).exclude(submission=submission).update(is_stale=True)

    # Classify only the newly-added prompt message, and only if not already classified
    if new_user_msg_id is not None and not Message.objects.filter(
        id=new_user_msg_id, prompt_level__isnull=False
    ).exists():
        threading.Thread(target=classify_message, args=(new_user_msg_id,), daemon=True).start()

    return {"id": str(submission.id)}


@router.get("/", response=List[SubmissionOut])
@paginate
@login_required
def list_submissions(request, filters: SubmissionFilter = Query(...)):
    """
    获取提交列表，支持按任务和用户过滤
    """
    submissions = (
        Submission.objects.select_related("task", "user")
        .defer("html", "css", "js")
    )

    if filters.task_id:
        task = get_object_or_404(Task, id=filters.task_id)
        submissions = submissions.filter(task=task)
    elif filters.task_type:
        submissions = submissions.filter(task__task_type=filters.task_type)
    if filters.username:
        submissions = submissions.filter(user__username__icontains=filters.username)
    if filters.user_id:
        submissions = submissions.filter(user_id=filters.user_id)
    if filters.flag:
        if filters.flag == "any":
            submissions = submissions.filter(flag__isnull=False)
        else:
            submissions = submissions.filter(flag=filters.flag)
    if filters.zone:
        submissions = submissions.filter(zone=filters.zone)

    if filters.score_lt_threshold is not None:
        submissions = submissions.filter(score__lt=filters.score_lt_threshold)
    else:
        if filters.score_min is not None:
            submissions = submissions.filter(score__gte=filters.score_min)
        if filters.score_max_exclusive is not None:
            submissions = submissions.filter(score__lt=filters.score_max_exclusive)
    if filters.ordering in ("-score", "score", "-created"):
        submissions = submissions.order_by(filters.ordering)

    if filters.grouped:
        # 分组模式：每个 (user, task) 只保留最新一条
        latest_per_group = (
            Submission.objects.filter(user=OuterRef("user"), task=OuterRef("task"))
            .order_by("-created")
            .values("pk")[:1]
        )
        submissions = submissions.filter(pk=Subquery(latest_per_group))

    user_rating_subquery = Subquery(
        Rating.objects.filter(user=request.user, submission=OuterRef("pk")).values(
            "score"
        )[:1],
        output_field=IntegerField(),
    )
    submissions = submissions.annotate(my_score=user_rating_subquery)

    # 同一用户同一任务的提交次数
    submit_count_subquery = Subquery(
        Submission.objects.filter(
            user=OuterRef("user"), task=OuterRef("task")
        ).values("user", "task").annotate(c=Count("id")).values("c")[:1],
        output_field=IntegerField(),
    )
    submissions = submissions.annotate(submit_count=submit_count_subquery)

    return submissions



@router.get("/by-user-task", response=List[SubmissionOut])
@login_required
def list_by_user_task(request, user_id: int, task_id: int):
    """
    获取某用户某任务的所有提交（不分页）
    """
    user_rating_subquery = Subquery(
        Rating.objects.filter(user=request.user, submission=OuterRef("pk")).values(
            "score"
        )[:1],
        output_field=IntegerField(),
    )
    return (
        Submission.objects.filter(user_id=user_id, task_id=task_id)
        .select_related("task", "user")
        .defer("html", "css", "js")
        .annotate(my_score=user_rating_subquery)
        .order_by("-created")
    )


@router.get("/random-for-rating/", response=Optional[RandomRatingOut])
@login_required
def get_random_for_rating(request, exclude_id: Optional[UUID] = None):
    """
    随机返回一个待打分的其他同学的提交（用于AI生成期间的随手打分弹窗）
    """
    if request.user.role == RoleChoices.NORMAL:
        today_start = timezone.now().replace(
            hour=0, minute=0, second=0, microsecond=0
        )
        today_end = today_start + timezone.timedelta(days=1)
        rating_count = Rating.objects.filter(
            user=request.user, created__range=(today_start, today_end)
        ).count()
        if rating_count >= 30:
            return None

    candidates = (
        Submission.objects.select_related("task", "user")
        .exclude(user=request.user)
        .exclude(ratings__user=request.user)
    )
    if exclude_id:
        candidates = candidates.exclude(pk=exclude_id)

    pending = candidates.annotate(rating_count=Count("ratings")).filter(
        rating_count__lt=5
    )
    return pending.order_by("?").first() or candidates.order_by("?").first()


@router.delete("/flags")
@login_required
def clear_all_flags(request):
    """
    清除所有提交的标记（仅管理员和超级管理员可操作）
    """
    if request.user.role not in (RoleChoices.SUPER, RoleChoices.ADMIN):
        raise HttpError(403, "没有权限")

    count = Submission.objects.filter(flag__isnull=False).update(flag=None)
    return {"cleared": count}


@router.delete("/{submission_id}")
@login_required
def delete_submission(request, submission_id: UUID):
    submission = get_object_or_404(Submission, id=submission_id)
    if submission.user != request.user and request.user.role != RoleChoices.SUPER:
        raise HttpError(403, "只能删除自己的提交")

    if request.user.role != RoleChoices.SUPER:
        has_ratings = Rating.objects.filter(submission=submission).exists()
        has_awards = SubmissionAward.objects.filter(submission=submission).exists()
        if has_ratings or has_awards:
            raise HttpError(400, "该提交已被评分或获奖，无法删除")

    # 找到关联的助手消息，再找前一条用户消息
    asst_msg = Message.objects.filter(submission=submission).first()
    user_msg = get_preceding_user_message(asst_msg) if asst_msg else None

    submission.delete()  # CASCADE 自动删除关联的 asst_msg

    if user_msg:
        user_msg.delete()

    return {"message": "删除成功"}


@router.get("/stats/{task_id}", response=TaskStatsOut)
@login_required
def get_task_stats(request, task_id: int, classname: Optional[str] = None):
    """
    获取某个挑战任务的班级提交统计数据（仅管理员）
    """
    if request.user.role not in (RoleChoices.SUPER, RoleChoices.ADMIN):
        raise HttpError(403, "没有权限")

    task = get_object_or_404(Task, id=task_id)

    # All distinct classnames (unfiltered, for filter buttons in UI)
    all_classes = list(
        User.objects.filter(role=RoleChoices.NORMAL)
        .exclude(classname="")
        .values_list("classname", flat=True)
        .distinct()
        .order_by("classname")
    )

    # Student universe: Normal users, optionally filtered by classname
    students = User.objects.filter(role=RoleChoices.NORMAL)
    if classname:
        students = students.filter(classname=classname)

    student_ids = list(students.values_list("id", flat=True))
    total_students = len(student_ids)

    # Submitted student IDs
    submitted_ids = set(
        Submission.objects.filter(task=task, user_id__in=student_ids)
        .values_list("user_id", flat=True)
        .distinct()
    )
    submitted_count = len(submitted_ids)
    unsubmitted_count = total_students - submitted_count

    # Unsubmitted users
    unsubmitted_users = [
        UserTag(username=u.username, classname=u.classname)
        for u in students.exclude(id__in=submitted_ids).order_by("classname", "username")
    ]

    # Latest submission per submitted user (SQLite-compatible).
    # Find each user's max created timestamp, then resolve all matching IDs
    # in a single query using OR'd Q objects instead of one query per user.
    latest_per_user = list(
        Submission.objects.filter(task=task, user_id__in=submitted_ids)
        .values("user_id")
        .annotate(max_created=Max("created"))
    )
    latest_sub_ids = []
    if latest_per_user:
        user_time_filter = Q()
        for row in latest_per_user:
            user_time_filter |= Q(user_id=row["user_id"], created=row["max_created"])
        # Fetch all matching submissions in one query; deduplicate by user_id
        seen_users: set = set()
        for sub_id, uid in (
            Submission.objects.filter(user_time_filter, task=task)
            .values_list("id", "user_id")
        ):
            if uid not in seen_users:
                seen_users.add(uid)
                latest_sub_ids.append(sub_id)
    latest_subs = list(Submission.objects.filter(id__in=latest_sub_ids))

    # Average score from latest submissions (None if no submissions have score > 0)
    avg_result = (
        Submission.objects.filter(id__in=latest_sub_ids, score__gt=0)
        .aggregate(avg=Avg("score"))["avg"]
    )
    average_score = round(avg_result, 2) if avg_result is not None else None

    # Unrated: submitted but no Rating on any of their submissions for this task
    rated_ids = set(
        Rating.objects.filter(
            submission__task=task, submission__user_id__in=submitted_ids
        )
        .values_list("submission__user_id", flat=True)
        .distinct()
    )
    unrated_ids = submitted_ids - rated_ids
    unrated_count = len(unrated_ids)
    unrated_users = [
        UserTag(username=u.username, classname=u.classname)
        for u in students.filter(id__in=unrated_ids).order_by("classname", "username")
    ]

    # Submission count distribution
    sub_counts = dict(
        Submission.objects.filter(task=task, user_id__in=submitted_ids)
        .values("user_id")
        .annotate(c=Count("id"))
        .values_list("user_id", "c")
    )
    dist = {"count_1": 0, "count_2": 0, "count_3": 0, "count_4_plus": 0}
    for c in sub_counts.values():
        if c == 1:
            dist["count_1"] += 1
        elif c == 2:
            dist["count_2"] += 1
        elif c == 3:
            dist["count_3"] += 1
        else:
            dist["count_4_plus"] += 1

    # Flag stats (all submissions for this task, not grouped by user)
    flag_counts = dict(
        Submission.objects.filter(task=task, flag__isnull=False)
        .values("flag")
        .annotate(c=Count("id"))
        .values_list("flag", "c")
    )
    flag_stats = FlagStats(
        red=flag_counts.get("red", 0),
        blue=flag_counts.get("blue", 0),
        green=flag_counts.get("green", 0),
        yellow=flag_counts.get("yellow", 0),
    )

    # Top 5 submissions by view_count (within filtered student_ids)
    top_viewed_qs = (
        Submission.objects
        .filter(task=task, user_id__in=student_ids)
        .select_related("user")
        .defer("html", "css", "js")
        .order_by("-view_count")[:5]
    )
    top_viewed = [
        TopViewedItem(
            username=s.user.username,
            classname=s.user.classname,
            view_count=s.view_count,
            submission_id=s.id,
        )
        for s in top_viewed_qs
    ]

    return TaskStatsOut(
        submitted_count=submitted_count,
        unsubmitted_count=unsubmitted_count,
        average_score=average_score,
        unrated_count=unrated_count,
        unsubmitted_users=unsubmitted_users,
        unrated_users=unrated_users,
        submission_count_distribution=SubmissionCountBucket(**dist),
        flag_stats=flag_stats,
        classes=all_classes,
        top_viewed=top_viewed,
    )


@router.get("/gradebook/", response=GradebookOut)
@super_required
def get_gradebook(
    request,
    classname: str = "",
    task_type: Optional[Literal["tutorial", "challenge"]] = None,
    username: Optional[str] = None,
    include_all_tasks: bool = False,
):
    return build_gradebook(
        GradebookFilters(
            classname=classname,
            task_type=task_type,
            username=username,
            include_all_tasks=include_all_tasks,
        )
    )


@router.get("/gradebook/export/")
@super_required
def export_gradebook(
    request,
    classname: str = "",
    task_type: Optional[Literal["tutorial", "challenge"]] = None,
    username: Optional[str] = None,
    include_all_tasks: bool = False,
):
    gradebook = build_gradebook(
        GradebookFilters(
            classname=classname,
            task_type=task_type,
            username=username,
            include_all_tasks=include_all_tasks,
        )
    )
    response = HttpResponse(content_type="text/csv; charset=utf-8")
    filename = f"gradebook-{gradebook['classname']}.csv"
    response["Content-Disposition"] = (
        f"attachment; filename*=UTF-8''{quote(filename)}"
    )
    response.write("\ufeff")
    writer = csv.writer(response)
    for row in gradebook_csv_rows(gradebook):
        writer.writerow(row)
    return response


@router.get("/showcase/", response=List[AwardOut])
@login_required
def list_showcase(request):
    ordering_map = {
        ItemOrdering.MANUAL: "sort_order",
        ItemOrdering.AWARDED_AT: "-awarded_at",
        ItemOrdering.SCORE: "-submission__score",
        ItemOrdering.VIEW_COUNT: "-submission__view_count",
    }
    awards = Award.objects.filter(is_active=True).order_by("sort_order")
    result = []

    for award in awards:
        order_field = ordering_map.get(award.item_ordering, "sort_order")
        items_qs = (
            SubmissionAward.objects.filter(award=award)
            .select_related("submission", "submission__user", "submission__task")
            .annotate(
                has_prompt_chain=Exists(
                    Message.objects.filter(submission_id=OuterRef("submission_id"))
                )
            )
            .order_by(order_field)
        )
        items = list(items_qs)
        if not items:
            continue
        result.append(
            {
                "id": award.id,
                "name": award.name,
                "description": award.description,
                "item_ordering": award.item_ordering,
                "items": [
                    {
                        "submission_id": sa.submission_id,
                        "username": sa.submission.user.username,
                        "task_title": sa.submission.task.title,
                        "task_display": sa.submission.task.display,
                        "score": sa.submission.score,
                        "view_count": sa.submission.view_count,
                        "html": sa.submission.html,
                        "css": sa.submission.css,
                        "js": sa.submission.js,
                        "has_prompt_chain": sa.has_prompt_chain,
                    }
                    for sa in items
                ],
            }
        )

    return result


@router.get("/showcase/manage/awards", response=List[AwardManageOut])
@admin_required
def list_manage_awards(request):
    awards = Award.objects.annotate(
        item_count=Count("submission_awards")
    ).order_by("sort_order", "id")
    return [_award_manage_out(award) for award in awards]


@router.post("/showcase/manage/awards", response=AwardManageOut)
@admin_required
def create_manage_award(request, payload: AwardManageIn):
    _validate_item_ordering(payload.item_ordering)
    award = Award.objects.create(**payload.dict())
    award.item_count = 0
    return _award_manage_out(award)


@router.put("/showcase/manage/awards/{award_id}", response=AwardManageOut)
@admin_required
def update_manage_award(request, award_id: int, payload: AwardManageIn):
    _validate_item_ordering(payload.item_ordering)
    award = get_object_or_404(Award, id=award_id)
    award.name = payload.name
    award.description = payload.description
    award.sort_order = payload.sort_order
    award.is_active = payload.is_active
    award.item_ordering = payload.item_ordering
    award.save(
        update_fields=[
            "name",
            "description",
            "sort_order",
            "is_active",
            "item_ordering",
        ]
    )
    award.item_count = award.submission_awards.count()
    return _award_manage_out(award)


@router.delete("/showcase/manage/awards/{award_id}")
@admin_required
def delete_manage_award(request, award_id: int):
    award = get_object_or_404(Award, id=award_id)
    award.delete()
    return {"message": "删除成功"}


@router.get(
    "/showcase/manage/submissions/{submission_id}",
    response=ShowcaseSubmissionLookupOut,
)
@admin_required
def get_manage_submission(request, submission_id: UUID):
    submission = get_object_or_404(
        Submission.objects.select_related("user", "task"),
        id=submission_id,
    )
    return _showcase_submission_lookup_out(submission)


@router.get(
    "/showcase/manage/awards/{award_id}/items",
    response=List[AwardItemManageOut],
)
@admin_required
def list_manage_award_items(request, award_id: int):
    award = get_object_or_404(Award, id=award_id)
    items = (
        SubmissionAward.objects.filter(award=award)
        .select_related("submission", "submission__user", "submission__task")
        .annotate(
            has_prompt_chain=Exists(
                Message.objects.filter(submission_id=OuterRef("submission_id"))
            )
        )
        .order_by(*_award_item_ordering(award))
    )
    return [_award_item_manage_out(item) for item in items]


@router.post(
    "/showcase/manage/awards/{award_id}/items",
    response=AwardItemManageOut,
)
@admin_required
def create_manage_award_item(request, award_id: int, payload: AwardItemIn):
    award = get_object_or_404(Award, id=award_id)
    submission = get_object_or_404(
        Submission.objects.select_related("user", "task"),
        id=payload.submission_id,
    )
    item, created = SubmissionAward.objects.get_or_create(
        award=award,
        submission=submission,
        defaults={"sort_order": payload.sort_order},
    )
    if not created:
        raise HttpError(400, "该作品已在奖项中")
    item.submission = submission
    return _award_item_manage_out(item)


@router.put("/showcase/manage/items/{item_id}", response=AwardItemManageOut)
@admin_required
def update_manage_award_item(request, item_id: int, payload: AwardItemUpdateIn):
    item = get_object_or_404(
        SubmissionAward.objects.select_related(
            "submission",
            "submission__user",
            "submission__task",
        ),
        id=item_id,
    )
    item.sort_order = payload.sort_order
    item.save(update_fields=["sort_order"])
    return _award_item_manage_out(item)


@router.delete("/showcase/manage/items/{item_id}")
@admin_required
def delete_manage_award_item(request, item_id: int):
    item = get_object_or_404(SubmissionAward, id=item_id)
    item.delete()
    return {"message": "删除成功"}


@router.put("/showcase/manage/items/{item_id}/refresh", response=AwardItemManageOut)
@admin_required
def refresh_manage_award_item(request, item_id: int):
    """切换创意工坊条目到该学生该挑战的最新提交"""
    item = get_object_or_404(
        SubmissionAward.objects.select_related(
            "submission", "submission__user", "submission__task"
        ),
        id=item_id,
    )
    latest = (
        Submission.objects.filter(
            user=item.submission.user,
            task=item.submission.task,
        )
        .order_by("-created")
        .first()
    )
    if latest and latest.pk != item.submission_id:
        item.submission = latest
    item.is_stale = False
    item.save(update_fields=["submission", "is_stale"])
    return _award_item_manage_out(item)


@router.get("/showcase/{submission_id}/", response=ShowcaseDetailOut)
@login_required
def get_showcase_detail(request, submission_id: UUID):
    if not SubmissionAward.objects.filter(
        submission_id=submission_id,
        award__is_active=True,
    ).exists():
        raise HttpError(404, "作品不存在或未授奖")

    sub = get_object_or_404(
        Submission.objects.select_related("user", "task"),
        id=submission_id,
    )
    has_chain = Message.objects.filter(submission=sub).exists()
    award_names = list(
        SubmissionAward.objects.filter(submission=sub)
        .filter(award__is_active=True)
        .select_related("award")
        .values_list("award__name", flat=True)
    )

    return {
        "submission_id": sub.id,
        "username": sub.user.username,
        "task_title": sub.task.title,
        "task_display": sub.task.display,
        "score": sub.score,
        "view_count": sub.view_count,
        "html": sub.html,
        "css": sub.css,
        "js": sub.js,
        "awards": award_names,
        "has_prompt_chain": has_chain,
    }


def _build_prompt_rounds(source_msg: Message):
    messages = list(source_msg.conversation.messages.all().order_by("created", "id"))
    try:
        source_index = messages.index(source_msg)
    except ValueError:
        source_index = len(messages) - 1
    messages = messages[: source_index + 1]

    rounds = []
    for i, msg in enumerate(messages):
        if msg.role != "user":
            continue
        html = css = js = None
        assistant_msg_id = None
        for reply in messages[i + 1:]:
            if reply.role == "user":
                break
            if reply.role == "assistant":
                assistant_msg_id = reply.id
                html = reply.code_html
                css = reply.code_css
                js = reply.code_js
                break
        rounds.append(
            {
                "question": msg.content,
                "source": msg.source,
                "prompt_level": msg.prompt_level,
                "assistant_msg_id": assistant_msg_id,
                "html": html,
                "css": css,
                "js": js,
            }
        )
    return rounds


@router.get("/showcase/{submission_id}/prompt-chain/", response=List[PromptRoundOut])
@login_required
def get_showcase_prompt_chain(request, submission_id: UUID):
    if not SubmissionAward.objects.filter(
        submission_id=submission_id,
        award__is_active=True,
    ).exists():
        raise HttpError(404, "作品不存在或未授奖")

    sub = get_object_or_404(Submission, id=submission_id)
    try:
        source_msg = Message.objects.select_related("conversation").get(submission=sub)
    except Message.DoesNotExist:
        raise HttpError(404, "该作品没有关联提示词链")

    return _build_prompt_rounds(source_msg)


@router.get("/{submission_id}/prompt-chain", response=List[PromptRoundOut])
@login_required
def get_submission_prompt_chain(request, submission_id: UUID):
    sub = get_object_or_404(Submission, id=submission_id)
    try:
        source_msg = Message.objects.select_related("conversation").get(submission=sub)
    except Message.DoesNotExist:
        raise HttpError(404, "该提交没有关联提示词链")

    return _build_prompt_rounds(source_msg)


@router.get("/{submission_id}", response=SubmissionOut)
@login_required
def get_submission(request, submission_id: UUID):
    """
    获取单个提交的详细信息
    """
    user_rating_subquery = Subquery(
        Rating.objects.filter(user=request.user, submission=OuterRef("pk")).values(
            "score"
        )[:1],
        output_field=IntegerField(),
    )
    submission = get_object_or_404(
        Submission.objects.select_related("task", "user").annotate(
            my_score=user_rating_subquery
        ),
        id=submission_id,
    )
    return submission


@router.post("/{submission_id}/view")
@login_required
def increment_view(request, submission_id: UUID):
    """
    增加提交的浏览次数（仅在全屏预览时调用）
    """
    updated = Submission.objects.filter(pk=submission_id).update(
        view_count=F("view_count") + 1
    )
    if not updated:
        raise HttpError(404, "提交不存在")
    return {"ok": True}


@router.put("/{submission_id}/score")
@login_required
def update_score(request, submission_id: UUID, payload: RatingScoreIn):
    """
    给提交打分
    """
    if payload.score <= 0:
        raise HttpError(400, "分数不能为零")

    submission = get_object_or_404(Submission, id=submission_id)

    _, created = Rating.objects.get_or_create(
        user=request.user,
        submission=submission,
        defaults={"score": payload.score},
    )

    if created:
        return {"message": "打分成功"}
    else:
        return {"message": "你已经给这个提交打过分了"}


@router.put("/{submission_id}/flag")
@login_required
def update_flag(request, submission_id: UUID, payload: FlagIn):
    """
    设置或清除提交的标记（仅管理员和超级管理员可操作）
    """
    if request.user.role not in (RoleChoices.SUPER, RoleChoices.ADMIN):
        raise HttpError(403, "没有权限")

    submission = get_object_or_404(Submission, id=submission_id)
    submission.flag = payload.flag
    submission.save(update_fields=["flag"])
    return {"flag": submission.flag}
