from __future__ import annotations

from datetime import date, timedelta


def is_off_day(current_date: date, holiday_dates: set[str]) -> bool:
    return current_date.weekday() >= 5 or current_date.isoformat() in holiday_dates

def get_shift_sequence(
    current_date: date,
    holiday_dates: set[str],
    daytime_shift2_only: bool = False,
) -> list[tuple[date, int]]:
    is_holiday = current_date.isoformat() in holiday_dates
    weekday = current_date.weekday()
    shifts: list[tuple[date, int]] = []

    if daytime_shift2_only and weekday < 5 and not is_holiday:
        return [(current_date, 2)]

    if is_off_day(current_date, holiday_dates):
        return [(current_date, 1), (current_date, 2), (current_date, 3)]

    shifts.append((current_date, 3))
    next_day = current_date + timedelta(days=1)
    if is_off_day(next_day, holiday_dates):
        cursor = next_day
        while is_off_day(cursor, holiday_dates):
            shifts.extend([(cursor, 1), (cursor, 2), (cursor, 3)])
            cursor += timedelta(days=1)
        shifts.append((cursor, 1))
        return shifts

    shifts.append((next_day, 1))
    return shifts


def get_shift_capacity_for_date(
    current_date: date,
    holiday_dates: set[str],
    daytime_shift2_only: bool = False,
) -> dict[int, int]:
    if daytime_shift2_only:
        return {1: 0, 2: 480, 3: 0}
    if is_off_day(current_date, holiday_dates):
        return {1: 480, 2: 480, 3: 480}
    return {1: 480, 2: 0, 3: 480}


def get_shift_sequence_with_capacity(
    current_date: date,
    holiday_dates: set[str],
    daytime_shift2_only: bool = False,
) -> tuple[list[tuple[date, int]], int]:
    shifts = get_shift_sequence(current_date, holiday_dates, daytime_shift2_only)
    capacity = sum(
        get_shift_capacity_for_date(day, holiday_dates, daytime_shift2_only).get(shift_index, 0)
        for day, shift_index in shifts
    )
    return shifts, capacity


def next_window_start_date(shifts: list[tuple[date, int]]) -> date:
    last_date, last_shift = shifts[-1]
    if last_shift in (1, 2):
        return last_date
    return last_date + timedelta(days=1)
