from typing import List

import graphene

from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
from vbv_lernwelt.feedback.models import FeedbackResponse
from vbv_lernwelt.feedback.utils import feedback_users


class FeedbackStatisticsSummaryType(graphene.ObjectType):
    _id = graphene.ID(required=True)
    satisfaction_average = graphene.Float(required=True)
    satisfaction_max = graphene.Int(required=True)
    total_responses = graphene.Int(required=True)


class FeedbackStatisticsRecordType(graphene.ObjectType):
    _id = graphene.ID(required=True)
    course_session_id = graphene.ID(required=True)
    generation = graphene.String(required=True)
    circle_id = graphene.ID(required=True)
    satisfaction_average = graphene.Float(required=True)
    satisfaction_max = graphene.Int(required=True)
    details_url = graphene.String(required=True)
    experts = graphene.String(required=True)


class FeedbackStatisticsResponsesType(graphene.ObjectType):
    _id = graphene.ID(required=True)
    records = graphene.List(
        graphene.NonNull(FeedbackStatisticsRecordType), required=True
    )
    summary = graphene.Field(FeedbackStatisticsSummaryType, required=True)


def feedback_responses(
    course_session_selection_ids: graphene.List(graphene.ID),
    course_id: graphene.ID,
    course_slug: graphene.String,
) -> FeedbackStatisticsResponsesType:
    # Get all course sessions for this user in the given course
    course_sessions = CourseSession.objects.filter(
        id__in=course_session_selection_ids,
    )

    circle_feedbacks = []
    total_responses = 0

    for course_session in course_sessions:
        fbs = FeedbackResponse.objects.filter(
            submitted=True,
            course_session=course_session,
            feedback_user__in=feedback_users(course_session.id),
        )

        total_responses += len(fbs)

        circle_feedbacks.extend(
            circle_feedback_average(
                feedbacks=fbs,
                course_session_id=course_session.id,
                generation=course_session.generation,
                course_slug=str(course_slug),
            )
        )

    if len(circle_feedbacks):
        avg = sum([fb.satisfaction_average for fb in circle_feedbacks]) / len(
            circle_feedbacks
        )
    else:
        avg = 0

    return FeedbackStatisticsResponsesType(
        _id=course_id,  # noqa
        records=circle_feedbacks,  # noqa
        summary=FeedbackStatisticsSummaryType(  # noqa
            _id=course_id,  # noqa
            satisfaction_average=avg,  # noqa
            satisfaction_max=4,  # noqa
            total_responses=total_responses,  # noqa
        ),
    )


def circle_feedback_average(
    feedbacks: List[FeedbackResponse],
    course_session_id,
    generation: str,
    course_slug: str,
):
    circle_data = {}
    records = []

    for fb in feedbacks:
        circle_id = fb.circle.id
        satisfaction = fb.data.get("satisfaction", None)

        if satisfaction is None:
            continue

        circle_data.setdefault(circle_id, {"total": 0, "count": 0, "experts": []})
        circle_data[circle_id]["total"] += satisfaction
        circle_data[circle_id]["count"] += 1

    for circle_id, data in circle_data.items():
        details_url = f"/course/{course_slug}/cockpit/feedback/{circle_id}?courseSessionId={course_session_id}"

        experts = CourseSessionUser.objects.filter(
            role="EXPERT",
            course_session_id=course_session_id,
            expert__id__in=[circle_id],
        ).values_list("user__first_name", "user__last_name")
        experts_names = [f"{first} {last}" for first, last in experts]

        records.append(
            FeedbackStatisticsRecordType(
                _id=f"circle:{circle_id}-course_session:{course_session_id}",  # noqa
                course_session_id=course_session_id,  # noqa
                generation=generation,  # noqa
                circle_id=circle_id,  # noqa
                satisfaction_average=data["total"] / data["count"],  # noqa
                satisfaction_max=4,  # noqa
                details_url=details_url,  # noqa
                experts=", ".join(experts_names),  # noqa
            )
        )

    return records
