#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Swimming Event Assignment Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def swimming_event_assignment():
    """Optimize swimmer assignments to events to maximize total performance score."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("swimming_event_assignment")
    
    # Data from the problem
    swimmers = [1, 2, 3]
    events = [1, 2, 3]
    
    # Performance scores (swimmer_id, event_id): score
    performance_scores = {
        (1, 1): 85.5,
        (2, 1): 78.3,
        (3, 1): 90.0,
        (1, 2): 0.0,  # Placeholder, not used in this example
        (2, 2): 0.0,  # Placeholder, not used in this example
        (3, 2): 0.0,  # Placeholder, not used in this example
        (1, 3): 0.0,  # Placeholder, not used in this example
        (2, 3): 0.0,  # Placeholder, not used in this example
        (3, 3): 0.0   # Placeholder, not used in this example
    }
    
    # Stadium capacities (event_id): capacity
    stadium_capacities = {
        1: 100,
        2: 150,
        3: 200
    }
    
    # CRITICAL: Validate array lengths before loops
    assert len(swimmers) == 3, "Swimmers array length mismatch"
    assert len(events) == 3, "Events array length mismatch"
    assert len(performance_scores) == 9, "Performance scores array length mismatch"
    assert len(stadium_capacities) == 3, "Stadium capacities array length mismatch"
    
    # 2. VARIABLES
    # Decision variables: x[s, e] = 1 if swimmer s is assigned to event e, 0 otherwise
    x = model.addVars(swimmers, events, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total performance score
    model.setObjective(
        gp.quicksum(performance_scores[s, e] * x[s, e] for s in swimmers for e in events),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Constraint 1: Swimmer Assignment Limit
    for s in swimmers:
        model.addConstr(
            gp.quicksum(x[s, e] for e in events) <= 1,
            name=f"swimmer_assignment_limit_{s}"
        )
    
    # Constraint 2: Event Capacity Constraint
    for e in events:
        model.addConstr(
            gp.quicksum(x[s, e] for s in swimmers) <= stadium_capacities[e],
            name=f"event_capacity_constraint_{e}"
        )
    
    # Constraint 3: Performance Score Threshold
    for s in swimmers:
        for e in events:
            if performance_scores[s, e] < 80:
                model.addConstr(
                    x[s, e] == 0,
                    name=f"performance_threshold_{s}_{e}"
                )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for s in swimmers:
            for e in events:
                if x[s, e].x > 0.5:
                    print(f"Swimmer {s} assigned to Event {e} with score {performance_scores[s, e]}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the optimization
if __name__ == "__main__":
    swimming_event_assignment()