#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Local Government Event Allocation Problem
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_event_allocation():
    """Optimize participant allocation to events to maximize satisfaction."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("local_govt_in_alabama")
    
    # Data from the problem
    events = [1, 2, 3]
    participants = [101, 102, 103]
    
    # Satisfaction scores
    satisfaction_scores = {
        (1, 101): 0.85,
        (1, 102): 0.75,
        (1, 103): 0.65,
        (2, 101): 0.7,
        (2, 102): 0.9,
        (2, 103): 0.8,
        (3, 101): 0.6,
        (3, 102): 0.85,
        (3, 103): 0.95
    }
    
    # Event capacities
    event_capacities = {
        1: 50,
        2: 100,
        3: 75
    }
    
    # CRITICAL: Validate array lengths before loops
    assert len(events) == len(event_capacities), "Event data mismatch"
    assert len(participants) == 3, "Participant data mismatch"
    
    # 2. VARIABLES
    # Binary decision variables: x[e, p] = 1 if participant p is assigned to event e
    x = model.addVars(events, participants, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total satisfaction score
    model.setObjective(gp.quicksum(satisfaction_scores[e, p] * x[e, p] for e in events for p in participants), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Event Capacity Constraints
    for e in events:
        model.addConstr(gp.quicksum(x[e, p] for p in participants) <= event_capacities[e], name=f"event_capacity_{e}")
    
    # Participant Assignment Constraints
    for p in participants:
        model.addConstr(gp.quicksum(x[e, p] for e in events) <= 1, name=f"participant_assignment_{p}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for e in events:
            for p in participants:
                if x[e, p].x > 0.5:
                    print(f"Participant {p} assigned to Event {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__":
    optimize_event_allocation()