import json

import graphene
import structlog
from rest_framework.exceptions import PermissionDenied

from vbv_lernwelt.assignment.graphql.types import AssignmentCompletionType
from vbv_lernwelt.assignment.models import Assignment
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, is_course_session_expert

logger = structlog.get_logger(__name__)


class AssignmentCompletionMutation(graphene.Mutation):
    assignment_completion = graphene.Field(AssignmentCompletionType)

    class Input:
        assignment_id = graphene.ID(required=True)
        course_session_id = graphene.ID(required=True)
        assignment_user_id = graphene.ID()

        completion_status = graphene.String()
        completion_data_string = graphene.String()

        evaluation_grade = graphene.Float()
        evaluation_points = graphene.Float()

    @classmethod
    def mutate(
        cls,
        root,
        info,
        assignment_id,
        course_session_id,
        assignment_user_id=None,
        completion_status="IN_PROGRESS",
        completion_data_string="{}",
        evaluation_grade=None,
        evaluation_points=None,
    ):
        if assignment_user_id is None:
            assignment_user_id = info.context.user.id

        assignment_user = User.objects.get(id=assignment_user_id)
        assignment = Assignment.objects.get(id=assignment_id)

        if not has_course_access(
            info.context.user,
            assignment.get_course().id,
        ):
            raise PermissionDenied()

        assignment_data = {
            "assignment_user": assignment_user,
            "assignment": assignment,
            "course_session": CourseSession.objects.get(id=course_session_id),
            "completion_data": json.loads(completion_data_string),
            "completion_status": completion_status,
        }

        evaluation_data = {}

        if completion_status in ["EVALUATION_SUBMITTED", "EVALUATION_IN_PROGRESS"]:
            if not is_course_session_expert(info.context.user, course_session_id):
                raise PermissionDenied()

            evaluation_data = {
                "evaluation_user": info.context.user,
                "evaluation_grade": evaluation_grade,
                "evaluation_points": evaluation_points,
            }

        ac = update_assignment_completion(
            copy_task_data=False,
            **assignment_data,
            **evaluation_data,
        )

        logger.debug(
            "AssignmentCompletionMutation 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,
        )

        return AssignmentCompletionMutation(assignment_completion=ac)


class AssignmentMutation:
    upsert_assignment_completion = AssignmentCompletionMutation.Field()
