# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_bodybuilder_performance():
    """Optimize the total weight lifted by bodybuilders in Snatch and Clean & Jerk events."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("body_builder_optimization")
    
    # Data from the database
    snatch_impact = [1.2, 1.3, 1.1]
    clean_jerk_impact = [1.5, 1.6, 1.4]
    performance_targets = [300.0, 320.0, 340.0]
    training_limits = [190.0, 210.0, 220.0]
    
    n_bodybuilders = len(performance_targets)
    
    # CRITICAL: Validate array lengths before loops
    assert len(snatch_impact) == len(clean_jerk_impact) == len(training_limits) == n_bodybuilders, "Array length mismatch"
    
    # 2. VARIABLES
    # Variables for weights lifted in Snatch and Clean & Jerk
    x_snatch = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_snatch_{i}", lb=0) 
                for i in range(n_bodybuilders)}
    x_clean_jerk = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_clean_jerk_{i}", lb=0) 
                    for i in range(n_bodybuilders)}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total weight lifted
    model.setObjective(gp.quicksum(x_snatch[i] + x_clean_jerk[i] for i in range(n_bodybuilders)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Performance Target Constraints
    for i in range(n_bodybuilders):
        model.addConstr(x_snatch[i] + x_clean_jerk[i] <= performance_targets[i], name=f"performance_target_{i}")
    
    # Training Impact Constraints
    for i in range(n_bodybuilders):
        model.addConstr(snatch_impact[i] * x_snatch[i] + clean_jerk_impact[i] * x_clean_jerk[i] <= training_limits[i], 
                        name=f"training_impact_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_bodybuilders):
            print(f"Bodybuilder {i+1}: Snatch = {x_snatch[i].x:.3f}, Clean & Jerk = {x_clean_jerk[i].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_bodybuilder_performance()