import graphene
from graphene.types.generic import GenericScalar
from graphene_django import DjangoObjectType
from rest_framework.exceptions import PermissionDenied

from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
from vbv_lernwelt.core.graphql.types import JSONStreamField
from vbv_lernwelt.course.graphql.interfaces import CoursePageInterface
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.iam.permissions import can_evaluate_assignments, has_course_access
from vbv_lernwelt.learnpath.graphql.types import LearningContentInterface
from vbv_lernwelt.media_files.graphql.types import ContentDocumentObjectType


class AssignmentCompletionObjectType(DjangoObjectType):
    completion_data = GenericScalar()
    task_completion_data = GenericScalar()
    learning_content_page_id = graphene.ID(source="learning_content_page_id")

    # rounded to sensible representation
    evaluation_points = graphene.Float()
    evaluation_max_points = graphene.Float()

    class Meta:
        model = AssignmentCompletion
        fields = (
            "id",
            "created_at",
            "updated_at",
            "submitted_at",
            "evaluation_submitted_at",
            "assignment_user",
            "assignment",
            "course_session",
            "learning_content_page_id",
            "completion_status",
            "completion_data",
            "evaluation_user",
            "additional_json_data",
            "edoniq_extended_time_flag",
            "evaluation_passed",
            "task_completion_data",
        )

    def resolve_evaluation_points(self, info):
        if self.evaluation_points:
            return round(self.evaluation_points, 1)  # noqa
        return None

    def resolve_evaluation_max_points(self, info):
        if self.evaluation_max_points:
            return round(self.evaluation_max_points, 1)  # noqa
        return None


class AssignmentObjectType(DjangoObjectType):
    tasks = JSONStreamField()
    evaluation_tasks = JSONStreamField()
    performance_objectives = JSONStreamField()
    max_points = graphene.Int()
    learning_content = graphene.Field(LearningContentInterface)
    completion = graphene.Field(
        AssignmentCompletionObjectType,
        course_session_id=graphene.ID(required=True),
        learning_content_page_id=graphene.ID(required=False),
        assignment_user_id=graphene.UUID(required=False),
    )
    solution_sample = graphene.Field(ContentDocumentObjectType)

    class Meta:
        model = Assignment
        interfaces = (CoursePageInterface,)
        fields = (
            "assignment_type",
            "needs_expert_evaluation",
            "intro_text",
            "effort_required",
            "evaluation_description",
            "evaluation_document_url",
            "learning_content",
            "competence_certificate",
        )

    def resolve_solution_sample(self, info):
        return self.solution_sample

    def resolve_max_points(self, info):
        return self.get_max_points()

    def resolve_learning_content(self, info):
        return self.find_attached_learning_content()

    def resolve_completion(
        self,
        info,
        course_session_id,
        learning_content_page_id=None,
        assignment_user_id=None,
    ):
        if learning_content_page_id is None:
            lp = self.find_attached_learning_content()
            if lp:
                learning_content_page_id = lp.id
        return resolve_assignment_completion(
            info=info,
            course_session_id=course_session_id,
            learning_content_page_id=learning_content_page_id,
            assignment_user_id=assignment_user_id,
            assignment_id=self.id,
        )


def resolve_assignment_completion(
    info,
    assignment_id,
    course_session_id,
    learning_content_page_id=None,
    assignment_user_id=None,
):
    if assignment_user_id is None:
        assignment_user_id = info.context.user.id

    if str(assignment_user_id) == str(info.context.user.id) or can_evaluate_assignments(
        evaluation_user=info.context.user,
        assignment_user_id=assignment_user_id,
        course_session_id=course_session_id,
    ):
        course_id = CourseSession.objects.get(id=course_session_id).course_id
        if has_course_access(info.context.user, course_id):
            if learning_content_page_id is None:
                learning_content_page = Assignment.objects.get(
                    id=assignment_id
                ).find_attached_learning_content()
                if learning_content_page:
                    learning_content_page_id = learning_content_page.id

            return AssignmentCompletion.objects.filter(
                assignment_user_id=assignment_user_id,
                assignment_id=assignment_id,
                learning_content_page_id=learning_content_page_id,
                course_session_id=course_session_id,
            ).first()
    raise PermissionDenied()
