import random
from datetime import datetime, timedelta

# 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 unavailable days for September
unavailable_days = {
    "NTALAMPEKOU": ["2024-09-12", "2024-09-13", "2024-09-14", "2024-09-15", "2024-09-16", "2024-09-17", "2024-09-18", "2024-09-19"],
    "MAFOUNI": ["2024-09-20", "2024-09-21", "2024-09-22", "2024-09-23", "2024-09-24", "2024-09-25"],
    "MEMIS": ["2024-09-01", "2024-09-02", "2024-09-03", "2024-09-04", "2024-09-05", "2024-09-06", "2024-09-07"],
    "RAISAKIS": ["2024-09-10", "2024-09-11", "2024-09-12", "2024-09-13", "2024-09-15", "2024-09-16", "2024-09-17"],
    "ENECHELIDOU": ["2024-09-12", "2024-09-13", "2024-09-14", "2024-09-15", "2024-09-16", "2024-09-17"],
    "DIMADIS": ["2024-09-05", "2024-09-06", "2024-09-07"],
    "SACHANIDOU": ["2024-09-21", "2024-09-22", "2024-09-23", "2024-09-24", "2024-09-25"],
    "VASILIADIS": ["2024-09-10", "2024-09-11", "2024-09-12", "2024-09-13", "2024-09-14", "2024-09-15"],
    "PAPAGEORGIOU": ["2024-09-01", "2024-09-02", "2024-09-03", "2024-09-04", "2024-09-05", "2024-09-06"],
    "KARAISKOS": ["2024-09-11", "2024-09-12", "2024-09-13", "2024-09-14", "2024-09-15"],
    "TSIPLAKIS": ["2024-09-15"],
    "SPANTIDAKIS": ["2024-09-14", "2024-09-15", "2024-09-16"],
    "PAPADOPOULOS": ["2024-09-12", "2024-09-13", "2024-09-14", "2024-09-15"],
    "LAZARIDOU": ["2024-09-01"],
    "KIKINIS": ["2024-09-02"],
    "GRIGORIADIS": ["2024-09-03"],
    "KOMNINOS": ["2024-09-04"],
    "KITSIS": ["2024-09-05"]
}

# Define previous month’s duties
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,
    "LAZARIDOU": 0,
    "KIKINIS": 0,
    "GRIGORIADIS": 0,
    "KOMNINOS": 0,
    "KITSIS": 0
}

# Predefined duties
predefined_duties = {
    "2024-09-10": "RAISAKIS",
    "2024-09-11": "KARAISKOS"  # Adjust as needed
}

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

# Function to reassign duties
def reassign_duties(primary_persons, date, month, schedule, primary_duties, predefined_duties, unavailable_days):
    # Reassign duties for primary persons to meet exact requirements if necessary
    for person in primary_persons:
        while primary_duties[person] < 3:
            next_available_date = date.replace(day=1) + timedelta(days=len(schedule))
            while next_available_date.month == month and primary_duties[person] < 3:
                date_str = next_available_date.strftime("%Y-%m-%d")
                if is_available(person, date_str, predefined_duties, unavailable_days):
                    # Assign duty
                    schedule[date_str] = person
                    primary_duties[person] += 1
                    total_duties[person] += 1
                next_available_date += timedelta(days=1)

    return schedule, primary_duties, secondary_duties, tertiary_duties, total_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)
    end_date = (datetime(year, month + 1, 1) - timedelta(days=1)).day
    
    # Initialize duty counters 
    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}
    total_duties = {p: 0 for p in primary_persons + secondary_persons + tertiary_persons}

    # Assign predefined duties
    for duty_date, person in predefined_duties.items():
        schedule[duty_date] = person
        total_duties[person] += 1

    # Assign duties on weekends
    for weekend in weekends:
        weekend_str = weekend.strftime("%Y-%m-%d")
        for person in primary_persons:
            if is_available(person, weekend_str, predefined_duties, unavailable_days) and primary_duties[person] < 3:
                schedule[weekend_str] = person
                primary_duties[person] += 1
                total_duties[person] += 1
                break  # Break after assigning to one primary person

    # 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]

            # Assign duties based on availability
            person = None
            if available_primary:
                person = random.choice(available_primary)
                primary_duties[person] += 1
            elif available_secondary:
                person = random.choice(available_secondary)
                secondary_duties[person] += 1
            elif available_tertiary:
                person = random.choice(available_tertiary)
                tertiary_duties[person] += 1
            
            if person:
                schedule[date_str] = person
                total_duties[person] += 1

        date += timedelta(days=1)  # Move to the next day

    # Reassign duties if primary persons do not meet the required number of duties
    schedule, primary_duties, secondary_duties, tertiary_duties, total_duties = reassign_duties(
        primary_persons, datetime(year, month, 1), month, schedule, primary_duties, predefined_duties, unavailable_days
    )
    
    return schedule, primary_duties, secondary_duties, tertiary_duties, total_duties

# Find weekends for the given month
def find_weekends(year, month):
    weekends = []
    for i in range(1, 32):
        try:
            day = datetime(year, month, i)
            if day.weekday() in [5, 6]:  # Saturday or Sunday
                weekends.append(day)
        except ValueError:
            break
    return weekends

# Example usage
weekends = find_weekends(2024, 9)
schedule, primary_duties, secondary_duties, tertiary_duties, total_duties = generate_schedule(
    month=9,
    year=2024,
    primary_persons=primary_persons,
    secondary_persons=secondary_persons,
    tertiary_persons=tertiary_persons,
    predefined_duties=predefined_duties,
    unavailable_days=unavailable_days,
    weekends=weekends
)

# Print the final schedule for September
for day, person in sorted(schedule.items()):
    print(f"{day}: {person}")

# Check availability for specific dates in September
dates_to_check = ["2024-09-29", "2024-09-30"]  # Example dates
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)]
    available_secondary = [p for p in secondary_persons if is_available(p, date_str, predefined_duties, unavailable_days)]
    available_tertiary = [p for p in tertiary_persons if is_available(p, date_str, predefined_duties, unavailable_days)]

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

# Print total duties for historical reference
print("\nTotal Duties History:")
for person, count in total_duties.items():
    print(f"{person}: {count} duties")
why i get: Traceback (most recent call last):
  File "/Users/chrismackom/Desktop/final14.py", line 154, in <module>
    schedule, primary_duties, secondary_duties, tertiary_duties, total_duties = generate_schedule(
  File "/Users/chrismackom/Desktop/final14.py", line 134, in generate_schedule
    schedule, primary_duties, secondary_duties, tertiary_duties, total_duties = reassign_duties(
  File "/Users/chrismackom/Desktop/final14.py", line 78, in reassign_duties
    return schedule, primary_duties, secondary_duties, tertiary_duties, total_duties
NameError: name 'secondary_duties' is not defined