from datetime import datetime, timedelta
import random

# Your predefined variables…
duty_date = "2024-08-11"
date = datetime.strptime(duty_date, "%Y-%m-%d")

day_of_week = date.strftime("%A")

# Finding weekends
weekends = [date + timedelta(days=i) for i in range((5 - date.weekday()) % 7, 31, 7)] + \
           [date + timedelta(days=i) for i in range((6 - date.weekday()) % 7, 31, 7)]

# Ensure weekends include the 30th and 31st if they fall on a weekend
for i in range(30, 32):
    potential_weekend = datetime(date.year, date.month, i)
    if potential_weekend.weekday() in [5, 6]:  # Saturday or Sunday
        weekends.append(potential_weekend)

print(day_of_week)
print(weekends)

# Define the list of persons for all three groups
primary_persons = ["NTALAMPEKOU", "MAFOUNI", "MEMIS", "RAISAKIS", "ENECHELIDOU", "DIMADIS"]
secondary_persons = ["SACHANIDOU", "VASILIADIS", "PAPAGEORGIOU", "KARAISKOS", "TSIPLAKIS", "SPANTIDAKIS", "PAPADOPOULOS"]
tertiary_persons = ["LAZARIDOU", "KIKINIS", "GRIGORIADIS", "KOMNINOS", "KITSIS"]

# Define the days they can’t be on duty (including the new group)
unavailable_days = {
    "NTALAMPEKOU": ["2024-08-12", "2024-08-13", "2024-08-14", "2024-08-15", "2024-08-16", "2024-08-17", "2024-08-18", "2024-08-19"],
    "MAFOUNI": ["2024-08-20", "2024-08-21", "2024-08-22", "2024-08-23", "2024-08-24", "2024-08-25"],
    "MEMIS": ["2024-08-01", "2024-08-02", "2024-08-03", "2024-08-04", "2024-08-05", "2024-08-06", "2024-08-07"],
    "RAISAKIS": ["2024-08-10", "2024-08-11", "2024-08-12", "2024-08-13", "2024-08-15", "2024-08-16", "2024-08-17"],
    "ENECHELIDOU": ["2024-08-12", "2024-08-13", "2024-08-14", "2024-08-15", "2024-08-16", "2024-08-17"],
    "DIMADIS": ["2024-08-05", "2024-08-06", "2024-08-07"],
    "SACHANIDOU": ["2024-08-21", "2024-08-22", "2024-08-23", "2024-08-24", "2024-08-25"],
    "VASILIADIS": ["2024-08-10", "2024-08-11", "2024-08-12", "2024-08-13", "2024-08-14", "2024-08-15"],
    "PAPAGEORGIOU": ["2024-08-01", "2024-08-02", "2024-08-03", "2024-08-04", "2024-08-05", "2024-08-07"],
    "KARAISKOS": ["2024-08-11", "2024-08-12", "2024-08-13", "2024-08-14", "2024-08-15"],
    "TSIPLAKIS": ["2024-08-15"],
    "SPANTIDAKIS": ["2024-08-14", "2024-08-15", "2024-08-16"],
    "PAPADOPOULOS": ["2024-08-12", "2024-08-13", "2024-08-14", "2024-08-15"],
    # New group
    "LAZARIDOU": ["2024-08-01"],
    "KIKINIS": ["2024-08-02"],
    "GRIGORIADIS": ["2024-08-03"],
    "KOMNINOS": ["2024-08-04"],
    "KITSIS": ["2024-08-05"]
}

# Define the history of previous months based on the table
previous_duties = {
    "NTALAMPEKOU": 24,
    "MAFOUNI": 22,
    "MEMIS": 22,
    "RAISAKIS": 24,
    "ENECHELIDOU": 0,
    "DIMADIS": 27,
    "SACHANIDOU": 9,
    "VASILIADIS": 12,
    "PAPAGEORGIOU": 11,
    "KARAISKOS": 11,
    "TSIPLAKIS": 8,
    "SPANTIDAKIS": 11,
    "PAPADOPOULOS": 22,
    # New group
    "LAZARIDOU": 0,
    "KIKINIS": 0,
    "GRIGORIADIS": 0,
    "KOMNINOS": 0,
    "KITSIS": 0
}

# Define the history of duties on specific days of the week (for new group)
weekly_duties = {
    "NTALAMPEKOU": {"Monday": 3, "Tuesday": 4, "Wednesday": 5, "Thursday": 5, "Friday": 1, "Saturday": 3, "Sunday": 3},
    "MAFOUNI": {"Monday": 2, "Tuesday": 5, "Wednesday": 5, "Thursday": 4, "Friday": 2, "Saturday": 2, "Sunday": 2},
    "MEMIS": {"Monday": 5, "Tuesday": 1, "Wednesday": 2, "Thursday": 2, "Friday": 4, "Saturday": 4, "Sunday": 4},
    "RAISAKIS": {"Monday": 2, "Tuesday": 3, "Wednesday": 6, "Thursday": 4, "Friday": 3, "Saturday": 4, "Sunday": 2},
    "ENECHELIDOU": {"Monday": 0, "Tuesday": 0, "Wednesday": 0, "Thursday": 0, "Friday": 0, "Saturday": 0, "Sunday": 0},
    "DIMADIS": {"Monday": 5, "Tuesday": 3, "Wednesday": 1, "Thursday": 3, "Friday": 5, "Saturday": 3, "Sunday": 7},
    "SACHANIDOU": {"Monday": 1, "Tuesday": 2, "Wednesday": 3, "Thursday": 0, "Friday": 1, "Saturday": 1, "Sunday": 1},
    "VASILIADIS": {"Monday": 1, "Tuesday": 2, "Wednesday": 0, "Thursday": 4, "Friday": 2, "Saturday": 1, "Sunday": 2},
    "PAPAGEORGIOU": {"Monday": 1, "Tuesday": 1, "Wednesday": 1, "Thursday": 2, "Friday": 2, "Saturday": 3, "Sunday": 1},
    "KARAISKOS": {"Monday": 1, "Tuesday": 3, "Wednesday": 2, "Thursday": 0, "Friday": 2, "Saturday": 2, "Sunday": 1},
    "TSIPLAKIS": {"Monday": 2, "Tuesday": 0, "Wednesday": 0, "Thursday": 1, "Friday": 2, "Saturday": 1, "Sunday": 2},
    "SPANTIDAKIS": {"Monday": 1, "Tuesday": 2, "Wednesday": 0, "Thursday": 2, "Friday": 3, "Saturday": 2, "Sunday": 1},
    "PAPADOPOULOS": {"Monday": 3, "Tuesday": 4, "Wednesday": 4, "Thursday": 3, "Friday": 2, "Saturday": 3, "Sunday": 3},
    # New group
    "LAZARIDOU": {"Monday": 0, "Tuesday": 0, "Wednesday": 0, "Thursday": 1, "Friday": 0, "Saturday": 1, "Sunday": 0},
    "KIKINIS": {"Monday": 0, "Tuesday": 0, "Wednesday": 0, "Thursday": 0, "Friday": 5, "Saturday": 0, "Sunday": 0},
    "GRIGORIADIS": {"Monday": 1, "Tuesday": 0, "Wednesday": 1, "Thursday": 1, "Friday": 1, "Saturday": 0, "Sunday": 0},
    "KOMNINOS": {"Monday": 0, "Tuesday": 0, "Wednesday": 1, "Thursday": 2, "Friday": 0, "Saturday": 2, "Sunday": 0},
    "KITSIS": {"Monday": 0, "Tuesday": 0, "Wednesday": 0, "Thursday": 0, "Friday": 0, "Saturday": 0, "Sunday": 0}
}

# Define the predefined duties
predefined_duties = {
    "2024-08-10": "RAISAKIS",
    "2024-08-11": "KARAISKOS"  # Adjust as needed
}

# Function to check availability
def is_available(person, date, predefined_duties, unavailable_days):
    return date not in unavailable_days.get(person, []) and date not in predefined_duties

# Generate Schedule Function
def generate_schedule(month, year, primary_persons, secondary_persons, tertiary_persons, predefined_duties, unavailable_days, weekends):
    schedule = {}
    date = datetime(year, month, 1)
    primary_duties = {p: 0 for p in primary_persons}
    secondary_duties = {p: 0 for p in secondary_persons}
    tertiary_duties = {p: 0 for p in tertiary_persons}
    previous_duties = {p: 0 for p in primary_persons + secondary_persons + tertiary_persons}
    weekly_duties = {p: {day: 0 for day in ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]} for p in primary_persons + secondary_persons + tertiary_persons}

    # Assign predefined duties
    for duty_date, person in predefined_duties.items():
        schedule[duty_date] = person
        if person in primary_duties:
            primary_duties[person] += 1
        elif person in secondary_duties:
            secondary_duties[person] += 1
        elif person in tertiary_duties:
            tertiary_duties[person] += 1

        previous_duties[person] += 1
        day_of_week = datetime.strptime(duty_date, "%Y-%m-%d").strftime("%A")
        weekly_duties[person][day_of_week] += 1

    # Shuffle weekends
    random.shuffle(weekends)
    
    # Assign duties on weekends
    for person in primary_persons:
        for weekend in weekends:
            weekend_date = weekend.strftime("%Y-%m-%d")
            if is_available(person, weekend_date, predefined_duties, unavailable_days):                    
                schedule[weekend_date] = person
                primary_duties[person] += 1
                previous_duties[person] += 1
                day_of_week = weekend.strftime("%A")
                weekly_duties[person][day_of_week] += 1
                weekends.remove(weekend)  # Remove the weekend once assigned
                break

    # Main scheduling loop
    while date.month == month:
        date_str = date.strftime("%Y-%m-%d")
        if date_str not in schedule:
            available_primary = [p for p in primary_persons if is_available(p, date_str, predefined_duties, unavailable_days) and primary_duties[p] < 3]
            available_secondary = [p for p in secondary_persons if is_available(p, date_str, predefined_duties, unavailable_days) and secondary_duties[p] < 2]
            available_tertiary = [p for p in tertiary_persons if is_available(p, date_str, predefined_duties, unavailable_days) and tertiary_duties[p] < 1]

            if available_primary:
                available_primary.sort(key=lambda p: (previous_duties.get(p, 0), weekly_duties[p][date.strftime("%A")]))
                person = available_primary[0]
                primary_duties[person] += 1
            elif available_secondary:
                available_secondary.sort(key=lambda p: (previous_duties.get(p, 0), weekly_duties[p][date.strftime("%A")]))
                person = available_secondary[0]
                secondary_duties[person] += 1
            elif available_tertiary:
                available_tertiary.sort(key=lambda p: (previous_duties.get(p, 0), weekly_duties[p][date.strftime("%A")]))
                person = available_tertiary[0]
                tertiary_duties[person] += 1
            else:
                person = None  # Handle the case where nobody is available
                print(f"No available duty person on {date_str}")  # Logging
            
            if person:
                schedule[date_str] = person
        
        date += timedelta(days=1)

    return schedule, primary_duties, secondary_duties, tertiary_duties

# Generate the schedule and also get the primary, secondary, and tertiary duties
schedule, primary_duties, secondary_duties, tertiary_duties = generate_schedule(8, 2024)  # August 2024

# Now you can check availability for specific dates
dates_to_check = ["2024-08-29", "2024-08-30"]
for date_str in dates_to_check:
    available_primary = [p for p in primary_persons if is_available(p, date_str, predefined_duties, unavailable_days) and primary_duties[p] < 3]
    available_secondary = [p for p in secondary_persons if is_available(p, date_str, predefined_duties, unavailable_days) and secondary_duties[p] < 2]
    available_tertiary = [p for p in tertiary_persons if is_available(p, date_str, predefined_duties, unavailable_days) and tertiary_duties[p] < 1]

    print(f"Date: {date_str}")
    print(f"Available Primary: {available_primary}")
    print(f"Available Secondary: {available_secondary}")
    print(f"Available Tertiary: {available_tertiary}")

# Print the final schedule
for day, person in sorted(schedule.items()):
    print(f"{day}: {person}")
i get this result : Sunday
[datetime.datetime(2024, 8, 17, 0, 0), datetime.datetime(2024, 8, 24, 0, 0), datetime.datetime(2024, 8, 31, 0, 0), datetime.datetime(2024, 9, 7, 0, 0), datetime.datetime(2024, 8, 11, 0, 0), datetime.datetime(2024, 8, 18, 0, 0), datetime.datetime(2024, 8, 25, 0, 0), datetime.datetime(2024, 9, 1, 0, 0), datetime.datetime(2024, 9, 8, 0, 0), datetime.datetime(2024, 8, 31, 0, 0)]
Traceback (most recent call last):
  File "/Users/chrismackom/Desktop/final9.py", line 179, in <module>
    schedule, primary_duties, secondary_duties, tertiary_duties = generate_schedule(8, 2024)  # August 2024
TypeError: generate_schedule() missing 6 required positional arguments: 'primary_persons', 'secondary_persons', 'tertiary_persons', 'predefined_duties', 'unavailable_days', and 'weekends'