#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Party People Optimization Problem
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_party_people():
    """Optimize the allocation of party members to events across regions."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("party_people")
    
    # Data from the problem
    regions = [1, 2, 3]
    influence_coefficients = {1: 0.6, 2: 0.7, 3: 0.5}
    total_members_available = {1: 20, 2: 25, 3: 15}
    max_events = {1: 5, 2: 6, 3: 4}
    min_members = {1: 5, 2: 6, 3: 4}
    min_events = {1: 1, 2: 2, 3: 1}
    cost_per_event = 6000
    total_budget = 150000
    
    # CRITICAL: Validate array lengths before loops
    assert len(regions) == len(influence_coefficients) == len(total_members_available) == len(max_events) == len(min_members) == len(min_events), "Array length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.INTEGER, name=f"x_{i}", lb=min_members[i], ub=total_members_available[i]) for i in regions}
    y = {i: model.addVar(vtype=GRB.INTEGER, name=f"y_{i}", lb=min_events[i], ub=max_events[i]) for i in regions}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(influence_coefficients[i] * x[i] for i in regions), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    # Budget Constraint
    model.addConstr(gp.quicksum(cost_per_event * y[i] for i in regions) <= total_budget, name="budget_constraint")
    
    # Member Assignment Upper Bound
    for i in regions:
        model.addConstr(x[i] <= total_members_available[i], name=f"member_upper_bound_{i}")
    
    # Member Assignment Lower Bound
    for i in regions:
        model.addConstr(x[i] >= min_members[i], name=f"member_lower_bound_{i}")
    
    # Event Organization Upper Bound
    for i in regions:
        model.addConstr(y[i] <= max_events[i], name=f"event_upper_bound_{i}")
    
    # Event Organization Lower Bound
    for i in regions:
        model.addConstr(y[i] >= min_events[i], name=f"event_lower_bound_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in regions:
            print(f"Region {i}: Members assigned = {x[i].x}, Events organized = {y[i].x}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the optimization
optimize_party_people()