from django.utils import timezone

from account.decorators import login_required
from flowchart.models import FlowchartSubmission, FlowchartSubmissionStatus
from flowchart.serializers import (
    CreateFlowchartSubmissionSerializer,
    FlowchartSubmissionListSerializer,
    FlowchartSubmissionSerializer,
)
from flowchart.tasks import evaluate_flowchart_task
from problem.models import Problem
from utils.api import AsyncAPIView


class FlowchartSubmissionAPI(AsyncAPIView):
    @login_required
    async def post(self, request):
        serializer = CreateFlowchartSubmissionSerializer(data=request.data)
        if not serializer.is_valid():
            return self.error(serializer.errors)

        data = serializer.validated_data

        try:
            problem = await Problem.objects.aget(id=data["problem_id"])
        except Problem.DoesNotExist:
            return self.error("Problem doesn't exist")

        if not problem.allow_flowchart:
            return self.error("This problem does not allow flowchart submission")

        submission = await FlowchartSubmission.objects.acreate(
            user=request.user,
            problem=problem,
            mermaid_code=data["mermaid_code"],
            flowchart_data=data.get("flowchart_data", {}),
        )

        evaluate_flowchart_task.send(submission.id)

        return self.success({"submission_id": submission.id, "status": "pending"})

    @login_required
    async def get(self, request):
        submission_id = request.GET.get("id")
        if not submission_id:
            return self.error("submission_id is required")

        try:
            submission = await FlowchartSubmission.objects.select_related("user", "problem").filter(id=submission_id).afirst()
            if submission is None:
                raise FlowchartSubmission.DoesNotExist
        except FlowchartSubmission.DoesNotExist:
            return self.error("Submission doesn't exist")

        if not submission.check_user_permission(request.user):
            return self.error("No permission for this submission")

        return self.success(await self.async_serialize_data(FlowchartSubmissionSerializer, submission))


class FlowchartSubmissionListAPI(AsyncAPIView):
    @login_required
    async def get(self, request):
        username = request.GET.get("username")
        problem_id = request.GET.get("problem_id")
        myself = request.GET.get("myself")

        queryset = FlowchartSubmission.objects.select_related("user", "problem")

        if problem_id:
            try:
                problem = await Problem.objects.aget(_id__iexact=problem_id, contest_id__isnull=True, visible=True)
            except Problem.DoesNotExist:
                return self.error("Problem doesn't exist")
            queryset = queryset.filter(problem=problem)

        if myself and myself == "1":
            queryset = queryset.filter(user=request.user)
        elif username:
            queryset = queryset.filter(user__username__icontains=username)
        elif request.user.is_regular_user():
            queryset = queryset.filter(user=request.user)

        if request.GET.get("today") == "1":
            now = timezone.now()
            queryset = queryset.filter(create_time__gte=now.replace(hour=0, minute=0, second=0, microsecond=0))

        grade = request.GET.get("grade")
        if grade in ("S", "A", "B", "C"):
            queryset = queryset.filter(ai_grade=grade)

        data = await self.async_paginate_data(request, queryset)
        data["results"] = await self.async_serialize_data(
            FlowchartSubmissionListSerializer,
            data["results"],
            many=True,
        )
        return self.success(data)


class FlowchartSubmissionRetryAPI(AsyncAPIView):
    @login_required
    async def post(self, request):
        submission_id = request.data.get("submission_id")
        if not submission_id:
            return self.error("submission_id is required")

        try:
            submission = await FlowchartSubmission.objects.select_related("problem").filter(id=submission_id).afirst()
            if submission is None:
                raise FlowchartSubmission.DoesNotExist
        except FlowchartSubmission.DoesNotExist:
            return self.error("Submission doesn't exist")

        if not submission.check_user_permission(request.user):
            return self.error("No permission for this submission")

        if submission.status not in [
            FlowchartSubmissionStatus.FAILED,
            FlowchartSubmissionStatus.COMPLETED,
        ]:
            return self.error("Submission is not in a state that allows retry")

        submission.status = FlowchartSubmissionStatus.PENDING
        submission.ai_score = None
        submission.ai_grade = None
        submission.ai_feedback = None
        submission.ai_suggestions = None
        submission.ai_criteria_details = {}
        submission.processing_time = None
        submission.evaluation_time = None
        await submission.asave()

        evaluate_flowchart_task.send(submission.id)

        return self.success(
            {
                "submission_id": submission.id,
                "status": "pending",
                "message": "AI evaluation restarted",
            }
        )


class FlowchartSubmissionDetailAPI(AsyncAPIView):
    @login_required
    async def get(self, request):
        problem_id = request.GET.get("problem_id")
        if not problem_id:
            return self.error("problem_id is required")
        try:
            problem = await Problem.objects.aget(id=problem_id)
        except Problem.DoesNotExist:
            return self.error("Problem doesn't exist")

        try:
            page = int(request.GET.get("page", 0))
        except ValueError:
            return self.error("page must be an integer")
        submissions = (
            FlowchartSubmission.objects.select_related("user", "problem")
            .filter(
                user=request.user,
                problem=problem,
                status=FlowchartSubmissionStatus.COMPLETED,
            )
            .order_by("create_time")
        )
        count = await submissions.acount()
        if count == 0:
            return self.success({"submission": None, "count": 0})
        if page == 0:
            submission = await submissions.alast()
        else:
            if page < 0 or page > count:
                return self.error("Page out of range")
            result = [s async for s in submissions[page - 1 : page]]
            submission = result[0]
        data = await self.async_serialize_data(FlowchartSubmissionSerializer, submission)
        return self.success({"submission": data, "count": count})


class FlowchartSubmissionCurrentAPI(AsyncAPIView):
    @login_required
    async def get(self, request):
        problem_id = request.GET.get("problem_id")
        if not problem_id:
            return self.error("problem_id is required")
        try:
            problem = await Problem.objects.aget(id=problem_id)
        except Problem.DoesNotExist:
            return self.error("Problem doesn't exist")
        submissions = (
            FlowchartSubmission.objects.filter(
                user=request.user,
                problem=problem,
                status=FlowchartSubmissionStatus.COMPLETED,
            )
            .values("ai_score", "ai_grade")
            .order_by("-create_time")
        )
        count = await submissions.acount()
        if count == 0:
            return self.success({"count": 0, "score": 0, "grade": ""})
        submission = await submissions.afirst()
        return self.success(
            {
                "count": count,
                "score": submission["ai_score"],
                "grade": submission["ai_grade"],
            }
        )
