from typing import List, Set, Tuple

import structlog

from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import Course
from vbv_lernwelt.learning_mentor.entities import (
    MentorAssignmentCompletion,
    MentorAssignmentStatus,
    MentorAssignmentStatusType,
    MentorCompletionStatus,
)
from vbv_lernwelt.learnpath.models import (
    LearningUnit,
    LearningUnitPerformanceFeedbackType,
)
from vbv_lernwelt.self_evaluation_feedback.models import SelfEvaluationFeedback

logger = structlog.get_logger(__name__)


def create_blank_completions_non_requesters(
    completions: List[MentorAssignmentCompletion],
    participants: List[User],
) -> List[MentorAssignmentCompletion]:
    non_requester_completions = []

    participants_user_ids = set([str(p.id) for p in participants])
    completion_seen_user_ids = set([str(c.user_id) for c in completions])

    user_by_id = {str(p.id): p for p in participants}
    for non_requester_user_id in participants_user_ids - completion_seen_user_ids:
        non_requester_user = user_by_id[non_requester_user_id]

        non_requester_completions.append(
            MentorAssignmentCompletion(
                status=MentorCompletionStatus.UNKNOWN,
                user_id=non_requester_user.id,
                last_name=non_requester_user.last_name,
                url="",
            )
        )

    return non_requester_completions


def get_self_feedback_evaluation(
    participants: List[User],
    evaluation_user: User,
    course: Course,
) -> Tuple[List[MentorAssignmentStatus], Set[int]]:
    records: List[MentorAssignmentStatus] = []
    circle_ids: Set[int] = set()

    if not participants:
        return records, circle_ids

    # very unfortunate: we can't simply get all SelfEvaluationFeedback objects since then
    # we would miss the one where no feedback was requested -> so we get all learning units
    # and check if we have to take them into account (course, feedback type, etc.)
    for learning_unit in LearningUnit.objects.filter(
        feedback_user=LearningUnitPerformanceFeedbackType.MENTOR_FEEDBACK.value,
        course_category__course_id=course.id,
    ):
        feedbacks = SelfEvaluationFeedback.objects.filter(
            learning_unit=learning_unit,
            feedback_requester_user__in=participants,
            feedback_provider_user=evaluation_user,
        )

        circle_id = learning_unit.get_circle().id
        circle_ids.add(circle_id)

        pending_evaluations = len([f for f in feedbacks if not f.feedback_submitted])

        completions = [
            MentorAssignmentCompletion(
                # feedback_submitted as seen from the perspective of the evaluation user (feedback provider)
                # means that the feedback has been evaluated by the feedback provider, hence the status is EVALUATED
                status=MentorCompletionStatus.EVALUATED
                if f.feedback_submitted
                else MentorCompletionStatus.SUBMITTED,
                user_id=f.feedback_requester_user.id,
                last_name=f.feedback_requester_user.last_name,
                url=f"/course/{course.slug}/cockpit/mentor/self-evaluation-feedback/{f.learning_unit.id}",
            )
            for f in feedbacks
        ]

        # requesting feedback is optional, so we need to add blank completions
        # for those mentees who did not request a feedback
        completions += create_blank_completions_non_requesters(
            completions=completions,
            participants=participants,
        )

        records.append(
            MentorAssignmentStatus(
                id=learning_unit.id,
                title=learning_unit.title,
                circle_id=circle_id,
                pending_evaluations=pending_evaluations,
                completions=completions,
                type=MentorAssignmentStatusType.SELF_EVALUATION_FEEDBACK,
            )
        )

    return records, circle_ids
