from collections import Counter

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

from api.models import TtSetting, TtStudent
from api.utils import get_resource_map_redis_data, recalculate_resource_map, recalculate_student_resource_map


def helper_recalculate_and_get_redis_resource_map(
        redis_data,
        staff_with_affected_week=None,
        location_with_affected_week=None,
        student_set_with_affected_week=None,
        student_ids=None,
        week_ids=None,
        slot_per_week=None,
        student_set_exclude_student=False
):
    """
    since this line of code always repeat, so having this helper to handle it, if next time got changes, can only change from this helper

    student_ids and week_ids must pass in tgt only will perform action for student resource map
    for student_ids and week_ids, most of the scenario can be None, if got update student set, will based on student set part to do
    just some scenario might only need update student resource map (eg. student update), so in those case only need pass in the student_ids and week_ids

    student_set_exclude_student when is True, after update student set, wont get student set student to update resource map
    """
    if slot_per_week is None:
        setting_params = {"slot_per_week"}
        settings = TtSetting.get_multiple_setting(setting_params)
        slot_per_week = int(settings["slot_per_week"])

    slot_per_week = int(slot_per_week)
    redis_staff_table = "staff"
    redis_location_table = "location"
    redis_student_set_table = "student_set"
    redis_student_table = "student"

    # update resource map
    staff_with_affected_week = {k: v for k, v in (staff_with_affected_week or {}).items() if v}
    location_with_affected_week = {k: v for k, v in (location_with_affected_week or {}).items() if v}
    student_set_with_affected_week = {k: v for k, v in (student_set_with_affected_week or {}).items() if v}
    week_ids = set(week_ids) if week_ids else set()
    student_ids = list(student_ids) if student_ids else []

    # Ensure "update" dictionary exists inside redis_data
    redis_data.setdefault("update", {})

    # recalculate resource map for affected_week and update data to redis
    if staff_with_affected_week:
        scheduled_staff_ids = list(staff_with_affected_week.keys())
        recalculate_resource_map("staff", staff_with_affected_week, slot_per_week)
        staff_resource_map_data = get_resource_map_redis_data("staff", scheduled_staff_ids)
        redis_data["update"].setdefault(redis_staff_table, []).extend(staff_resource_map_data)
    if location_with_affected_week:
        scheduled_location_ids = list(location_with_affected_week.keys())
        recalculate_resource_map("location", location_with_affected_week, slot_per_week)
        location_resource_map_data= get_resource_map_redis_data("location", scheduled_location_ids)
        redis_data["update"].setdefault(redis_location_table, []).extend(location_resource_map_data)
    if student_set_with_affected_week:
        scheduled_student_set_ids = list(student_set_with_affected_week.keys())
        recalculate_resource_map("student_set", student_set_with_affected_week, slot_per_week)

        student_set_resource_map_data = get_resource_map_redis_data("student_set",scheduled_student_set_ids)
        redis_data["update"].setdefault(redis_student_set_table, []).extend(student_set_resource_map_data)
        if not student_ids and not week_ids and not student_set_exclude_student:
            # when no passing in student_with_affected_week but got update student set, then need have query to get student from those student set
            student_ids = list(
                TtStudent.objects.filter(student_set__id__in=scheduled_student_set_ids)
                .values_list("id", flat=True)
                .distinct()
            )
            for weeks in student_set_with_affected_week.values():
                week_ids.update(weeks)

    if student_ids and week_ids:
        recalculate_student_resource_map(student_ids,week_ids,slot_per_week)
        student_resource_map_data = get_resource_map_redis_data("student",student_ids)
        redis_data["update"].setdefault(redis_student_table, []).extend(student_resource_map_data)

    return redis_data
