from typing import List, Tuple

import graphene
from wagtail.models import Page

from vbv_lernwelt.course.models import CourseCompletion, CourseCompletionStatus


class CompetencePerformanceStatisticsSummaryType(graphene.ObjectType):
    _id = graphene.ID(required=True)
    success_total = graphene.Int(required=True)
    fail_total = graphene.Int(required=True)


class CompetenceRecordStatisticsType(graphene.ObjectType):
    _id = graphene.ID(required=True)
    course_session_id = graphene.ID(required=True)
    generation = graphene.String(required=True)
    title = graphene.String(required=True)
    circle_id = graphene.ID(required=True)
    success_count = graphene.Int(required=True)
    fail_count = graphene.Int(required=True)
    details_url = graphene.String(required=True)


class CompetencesStatisticsType(graphene.ObjectType):
    _id = graphene.ID(required=True)
    summary = graphene.Field(CompetencePerformanceStatisticsSummaryType, required=True)
    records = graphene.List(
        graphene.NonNull(CompetenceRecordStatisticsType), required=True
    )


def competences(
    course_session_selection_ids: List[str],
    course_slug: str,
    user_selection_ids: List[str] | None = None,
) -> Tuple[List[CompetenceRecordStatisticsType], int, int]:
    completions = CourseCompletion.objects.filter(
        course_session_id__in=course_session_selection_ids,
        page_type="competence.PerformanceCriteria",
    ).prefetch_related("course_session", "page")

    if user_selection_ids is not None:
        completions = completions.filter(user_id__in=user_selection_ids)

    competence_records = {}

    unique_page_ids = {completion.page.id for completion in completions}
    learning_units = {
        page_id: Page.objects.get(id=page_id).specific.learning_unit
        for page_id in unique_page_ids
    }
    circles = {lu.id: lu.get_circle() for lu in learning_units.values()}

    for completion in completions:
        learning_unit = learning_units.get(completion.page.id)
        circle = circles.get(learning_unit.id)

        combined_id = f"{circle.id}-{completion.course_session.id}"

        competence_records.setdefault(combined_id, {}).setdefault(
            learning_unit,
            CompetenceRecordStatisticsType(
                _id=combined_id,  # noqa
                title=learning_unit.title,  # noqa
                course_session_id=completion.course_session.id,  # noqa
                generation=completion.course_session.generation,  # noqa
                circle_id=circle.id,  # noqa
                success_count=0,  # noqa
                fail_count=0,  # noqa
                details_url=f"/course/{course_slug}/cockpit?courseSessionId={completion.course_session.id}",
                # noqa
            ),
        )

        if completion.completion_status == CourseCompletionStatus.SUCCESS.value:
            competence_records[combined_id][learning_unit].success_count += 1
        elif completion.completion_status == CourseCompletionStatus.FAIL.value:
            competence_records[combined_id][learning_unit].fail_count += 1

    values = [
        record
        for circle_records in competence_records.values()
        for record in circle_records.values()
    ]

    success_count = sum([c.success_count for c in values])
    fail_count = sum([c.fail_count for c in values])

    return values, success_count, fail_count
