import structlog
from rest_framework.decorators import api_view
from rest_framework.exceptions import PermissionDenied
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response
from wagtail.models import Page

from vbv_lernwelt.assignment.models import AssignmentCompletion
from vbv_lernwelt.assignment.serializers import AssignmentCompletionSerializer
from vbv_lernwelt.assignment.services import update_assignment_completion
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course.permissions import (
    has_course_access,
    has_course_access_by_page_request,
    is_course_session_expert,
)

logger = structlog.get_logger(__name__)


def _request_assignment_completion(
    assignment_id, course_session_id, assignment_user_id
):
    try:
        response_data = AssignmentCompletionSerializer(
            AssignmentCompletion.objects.get(
                assignment_user_id=assignment_user_id,
                assignment_id=assignment_id,
                course_session_id=course_session_id,
            ),
        ).data

        return Response(status=200, data=response_data)
    except Exception as e:
        logger.error(e)
        return Response({"error": str(e)}, status=404)


@api_view(["GET"])
def request_assignment_completion(request, assignment_id, course_session_id):
    course_id = get_object_or_404(CourseSession, id=course_session_id).course_id
    if has_course_access(request.user, course_id):
        return _request_assignment_completion(
            assignment_id=assignment_id,
            course_session_id=course_session_id,
            assignment_user_id=request.user.id,
        )
    raise PermissionDenied()


@api_view(["GET"])
def request_assignment_completion_for_user(
    request, assignment_id, course_session_id, user_id
):
    if request.user.id == user_id or is_course_session_expert(
        request.user, course_session_id
    ):
        return _request_assignment_completion(
            assignment_id=assignment_id,
            course_session_id=course_session_id,
            assignment_user_id=user_id,
        )
    raise PermissionDenied()


@api_view(["GET"])
def request_assignment_completion_status(request, assignment_id, course_session_id):
    # TODO quickfix before GraphQL...
    if is_course_session_expert(request.user, course_session_id):
        qs = AssignmentCompletion.objects.filter(
            course_session_id=course_session_id,
            assignment_id=assignment_id,
        ).values("id", "assignment_user_id", "completion_status", "evaluation_grade")
        return Response(status=200, data=qs)

    raise PermissionDenied()


@api_view(["POST"])
def upsert_user_assignment_completion(request):
    try:
        assignment_id = request.data.get("assignment_id")
        course_session_id = request.data.get("course_session_id")
        completion_status = request.data.get("completion_status", "IN_PROGRESS")
        completion_data = request.data.get("completion_data", {})

        assignment_page = Page.objects.get(id=assignment_id)

        if not has_course_access_by_page_request(request, assignment_page):
            raise PermissionDenied()

        assignment = assignment_page.specific

        ac = update_assignment_completion(
            assignment_user=request.user,
            assignment=assignment,
            course_session=CourseSession.objects.get(id=course_session_id),
            completion_data=completion_data,
            completion_status=completion_status,
            copy_task_data=False,
        )

        logger.debug(
            "upsert_user_assignment_completion successful",
            label="assignment_api",
            assignment_id=assignment.id,
            assignment_title=assignment.title,
            assignment_user_id=request.user.id,
            course_session_id=course_session_id,
            completion_status=completion_status,
        )

        return Response(status=200, data=AssignmentCompletionSerializer(ac).data)
    except PermissionDenied as e:
        raise e
    except Exception as e:
        logger.error(e, exc_info=True)
        return Response({"error": str(e)}, status=404)


@api_view(["POST"])
def evaluate_assignment_completion(request):
    try:
        assignment_id = request.data.get("assignment_id")
        assignment_user_id = request.data.get("assignment_user_id")
        course_session_id = request.data.get("course_session_id")
        completion_status = request.data.get(
            "completion_status", "EVALUATION_IN_PROGRESS"
        )
        completion_data = request.data.get("completion_data", {})
        evaluation_grade = request.data.get("evaluation_grade", None)
        evaluation_points = request.data.get("evaluation_grade", None)

        assignment_page = Page.objects.get(id=assignment_id)
        assignment_user = User.objects.get(id=assignment_user_id)

        if not has_course_access_by_page_request(request, assignment_page):
            raise PermissionDenied()

        if not is_course_session_expert(request.user, course_session_id):
            raise PermissionDenied()

        assignment = assignment_page.specific

        ac = update_assignment_completion(
            assignment_user=assignment_user,
            assignment=assignment,
            course_session=CourseSession.objects.get(id=course_session_id),
            completion_data=completion_data,
            completion_status=completion_status,
            copy_task_data=False,
            evaluation_user=request.user,
            evaluation_grade=evaluation_grade,
            evaluation_points=evaluation_points,
        )

        logger.debug(
            "grade_assignment_completion successful",
            label="assignment_api",
            assignment_id=assignment.id,
            assignment_title=assignment.title,
            assignment_user_id=assignment_user_id,
            course_session_id=course_session_id,
            completion_status=completion_status,
            evaluation_user_id=request.user.id,
            evaluation_grade=evaluation_grade,
            evaluation_points=evaluation_points,
        )

        return Response(status=200, data=AssignmentCompletionSerializer(ac).data)
    except PermissionDenied as e:
        raise e
    except Exception as e:
        logger.error(e, exc_info=True)
        return Response({"error": str(e)}, status=404)
