import itertools
from typing import Iterable, Optional

from sqlalchemy.orm import Session

from watcher.db import Shift
from watcher.crud.gap import get_staff_gaps_for_interval
from watcher.crud.manual_gap import get_staff_manual_gaps_for_schedule_group
from watcher.logic.people_allocation import find_intersecting_gap


def find_shift_with_staff_without_intersection(
    db: Session, shifts: Iterable[Shift], target_shift: Shift
) -> Optional[Shift]:
    """
    :param shifts: шифты, участники которых рассматриваются в качестве кандидата на дежурство
    :param target_shift: шифт, для которого ищем нового дежурного
    :return: подходящий шифт из shifts или None
    """
    staff_ids = {obj.staff_id for obj in shifts if obj.staff_id}
    duty_gaps = get_staff_gaps_for_interval(
        db=db, staff_ids=staff_ids,
        start=target_shift.start, end=target_shift.end,
    )
    manual_gaps = get_staff_manual_gaps_for_schedule_group(
        db=db, staff_ids=staff_ids,
        start=target_shift.start, end=target_shift.end,
        service_ids=[target_shift.schedule.service_id],
        schedule_group_id=target_shift.schedule.schedules_group_id,
    )
    for obj in shifts:
        if not obj.staff:
            continue
        has_intersection = find_intersecting_gap(
            participant_gaps=itertools.chain(duty_gaps[obj.staff_id], manual_gaps[obj.staff_id]),
            shift=target_shift,
        )
        if not has_intersection:
            return obj
