from collections import Counter

from django.db import transaction
from django.db.models import Prefetch

from api.models import TtActivitySequencing, TtStudent, TtStudentPosModule, TtPathway, TtStudentPathway


def helper_pathway_generate_assign_student_to_pathway(pos_id, inserted_pathway_ids=None,exclude_pathway_planned_size=False):
    """
    :param inserted_pathway_ids: OPTIONAL, list of pathway_id need to update planned size, if not given, just wont update the planned_size
    2026-08-28
    currently used for pathway_generate and pathway_manual_generate
    """
    batch_size = 500
    filter_for_pos_modules = TtStudentPosModule.objects.filter(
        pos_module_group_module__pos_module_group__pos_id=pos_id
    ).select_related("pos_module_group_module__module")

    # only get student that have join the pos, and dun have pathway in target pos
    students = TtStudent.objects.filter(pos__id=pos_id).exclude(pathway__pos_id=pos_id).prefetch_related(
        "pos",
        Prefetch(
            "ttstudentposmodule_set",
            queryset=filter_for_pos_modules
        )
    )

    pathway_map = dict(
        TtPathway.objects.filter(pos_id=pos_id)
        .exclude(pathway_string=None)
        .values_list("pathway_string", "id")
    )

    student_pathway_idata = []
    update_new_pathway_planned_size = {}
    pathway_student_counts = Counter()
    for student in students:
        pos_module_group_module_ids = []
        for student_pos_module in student.ttstudentposmodule_set.all():
            pos_module_group_module_ids.append(student_pos_module.pos_module_group_module_id)

        # skip user just join pos, but no module
        if not pos_module_group_module_ids:
            continue
        pathway_string = ";".join(map(str, sorted(pos_module_group_module_ids)))

        pathway_id = pathway_map.get(pathway_string)
        if pathway_id:
            # only new created pathway need update planned size
            if pathway_id in inserted_pathway_ids:
                pathway_student_counts[pathway_id] += 1
            student_pathway_idata.append({
                "pathway_id": pathway_id,
                "student_id": student.id
            })

    if student_pathway_idata:
        student_pathway_objects = [TtStudentPathway(**data) for data in student_pathway_idata]
        with transaction.atomic():
            for i in range(0, len(student_pathway_objects), batch_size):
                TtStudentPathway.objects.bulk_create(
                    student_pathway_objects[i:i + batch_size],
                    batch_size=batch_size,
                    ignore_conflicts=True
                )

        # got insert student pathway relation only need do this action
        affected_pathway_ids = list(pathway_student_counts.keys())
        # normally only manual generate pathway, exclude_pathway_planned_size will be True
        if affected_pathway_ids and not exclude_pathway_planned_size:
            latest_inserted_pathways = TtPathway.objects.filter(id__in=affected_pathway_ids)
            for inserted_pathway in latest_inserted_pathways:
                inserted_pathway.planned_size = pathway_student_counts[inserted_pathway.id]
            TtPathway.objects.bulk_update(latest_inserted_pathways, fields=['planned_size'])