# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_movie_promotion():
    """Optimize promotional budget allocation for movies to maximize ratings increase."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("movie_promotion")
    
    # Data: Sensitivity values and minimum budget requirements
    sensitivity = [0.15, 0.25, 0.1]
    min_budget = [20000, 30000, 15000]
    total_budget = 65000
    n_movies = len(sensitivity)
    
    # CRITICAL: Validate array lengths before loops
    assert len(sensitivity) == len(min_budget) == n_movies, "Array length mismatch"
    
    # 2. VARIABLES
    # Variable dictionaries for budget allocation
    budget_allocation = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i+1}", lb=0) 
                         for i in range(n_movies)}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the expected increase in movie ratings
    model.setObjective(gp.quicksum(sensitivity[i] * budget_allocation[i] for i in range(n_movies)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Total budget constraint
    model.addConstr(gp.quicksum(budget_allocation[i] for i in range(n_movies)) <= total_budget, name="total_budget")
    
    # Minimum budget constraints for each movie
    for i in range(n_movies):
        model.addConstr(budget_allocation[i] >= min_budget[i], name=f"min_budget_{i+1}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_movies):
            if budget_allocation[i].x > 1e-6:
                print(f"Budget allocation for movie {i+1}: {budget_allocation[i].x:.2f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_movie_promotion()