from typing import List, Set, Tuple

from vbv_lernwelt.assignment.models import (
    Assignment,
    AssignmentCompletion,
    AssignmentCompletionStatus,
    AssignmentType,
)
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course_session.models import CourseSessionAssignment
from vbv_lernwelt.learning_mentor.entities import (
    MentorAssignmentCompletion,
    MentorAssignmentStatus,
    MentorAssignmentStatusType,
    MentorCompletionStatus,
)


def get_assignment_completions(
    course_session: CourseSession,
    assignment: Assignment,
    participants: List[User],
    evaluation_user: User,
) -> List[MentorAssignmentCompletion]:
    evaluation_results = AssignmentCompletion.objects.filter(
        assignment_user__in=participants,
        course_session=course_session,
        assignment=assignment,
        evaluation_user=evaluation_user,
    ).values("completion_status", "assignment_user__last_name", "assignment_user")

    user_status_map = {}
    for result in evaluation_results:
        completion_status = result["completion_status"]

        if completion_status == AssignmentCompletionStatus.EVALUATION_SUBMITTED.value:
            status = MentorCompletionStatus.EVALUATED
        elif completion_status in [
            AssignmentCompletionStatus.SUBMITTED.value,
            AssignmentCompletionStatus.EVALUATION_IN_PROGRESS.value,
        ]:
            status = MentorCompletionStatus.SUBMITTED
        else:
            status = MentorCompletionStatus.UNKNOWN

        user_status_map[result["assignment_user"]] = (
            status,
            result["assignment_user__last_name"],
        )

    status_priority = {
        MentorCompletionStatus.SUBMITTED: 1,
        MentorCompletionStatus.EVALUATED: 2,
        MentorCompletionStatus.UNKNOWN: 3,
    }

    sorted_participants = sorted(
        participants,
        key=lambda u: (
            status_priority.get(
                user_status_map.get(u.id, (MentorCompletionStatus.UNKNOWN, ""))[0]
            ),
            user_status_map.get(u.id, ("", u.last_name))[1],
        ),
    )

    return [
        MentorAssignmentCompletion(
            status=user_status_map.get(
                user.id, (MentorCompletionStatus.UNKNOWN, user.last_name)
            )[0],
            user_id=user.id,
            last_name=user.last_name,
            url=f"/course/{course_session.course.slug}/cockpit/assignment/{assignment.id}/{user.id}",
        )
        for user in sorted_participants
    ]


def get_praxis_assignments(
    course_session: CourseSession, participants: List[User], evaluation_user: User
) -> Tuple[List[MentorAssignmentStatus], Set[int]]:
    records = []
    circle_ids = set()

    if not participants:
        return records, circle_ids

    for course_session_assignment in CourseSessionAssignment.objects.filter(
        course_session=course_session,
        learning_content__assignment_type__in=[
            AssignmentType.PRAXIS_ASSIGNMENT.value,
        ],
    ):
        learning_content = course_session_assignment.learning_content

        completions = get_assignment_completions(
            course_session=course_session,
            assignment=learning_content.content_assignment,
            participants=participants,
            evaluation_user=evaluation_user,
        )

        submitted_count = len(
            [
                completion
                for completion in completions
                if completion.status == MentorCompletionStatus.SUBMITTED
            ]
        )

        circle_id = learning_content.get_circle().id

        records.append(
            MentorAssignmentStatus(
                id=course_session_assignment.id,
                title=learning_content.content_assignment.title,
                circle_id=circle_id,
                pending_evaluations=submitted_count,
                completions=completions,
                type=MentorAssignmentStatusType.PRAXIS_ASSIGNMENT,
            )
        )

        circle_ids.add(circle_id)

    return records, circle_ids
