#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Scholarship Allocation Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def scholarship_optimization():
    """Optimize scholarship allocation based on academic performance, sports participation, and gaming habits."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("scholarship_allocation")
    
    # Data from the provided schema
    student_ids = [1, 2, 3]
    gpa = {1: 3.8, 2: 3.5, 3: 3.2}
    hours_sports = {1: 10.0, 2: 7.5, 3: 5.0}
    hours_gaming = {1: 12.5, 2: 15.0, 3: 10.0}
    min_hours_sports = {1: 2.0, 2: 2.5, 3: 3.0}
    max_hours_sports = {1: 15.0, 2: 18.0, 3: 20.0}
    min_hours_gaming = {1: 5.0, 2: 6.0, 3: 5.5}
    max_hours_gaming = {1: 20.0, 2: 25.0, 3: 22.0}
    weights = {'w1': 0.6, 'w2': 0.25, 'w3': 0.15}
    total_budget = 150000
    
    # CRITICAL: Validate array lengths before loops
    assert len(student_ids) == len(gpa) == len(hours_sports) == len(hours_gaming), "Array length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=0) for i in student_ids}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(
        gp.quicksum((weights['w1'] * gpa[i] + weights['w2'] * hours_sports[i] + weights['w3'] * hours_gaming[i]) * x[i] for i in student_ids),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Total Budget Constraint
    model.addConstr(gp.quicksum(x[i] for i in student_ids) <= total_budget, name="total_budget")
    
    # Scholarship Fairness Constraint
    for i in student_ids:
        model.addConstr(x[i] >= 1000 * gpa[i], name=f"fairness_{i}")
    
    # Sports Participation Constraints
    for i in student_ids:
        model.addConstr(hours_sports[i] >= min_hours_sports[i], name=f"min_sports_{i}")
        model.addConstr(hours_sports[i] <= max_hours_sports[i], name=f"max_sports_{i}")
    
    # Gaming Habits Constraints
    for i in student_ids:
        model.addConstr(hours_gaming[i] >= min_hours_gaming[i], name=f"min_gaming_{i}")
        model.addConstr(hours_gaming[i] <= max_hours_gaming[i], name=f"max_gaming_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in student_ids:
            print(f"Scholarship for student {i}: ${x[i].x:.2f}")
    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__":
    scholarship_optimization()