# Complete DOCPLEX implementation

from docplex.mp.model import Model

def optimize_student_engagement():
    """Optimize student engagement by allocating hours to games and sports."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="student_engagement")
    
    # Sample data based on the provided problem context
    students = [1, 2, 3]
    games = [101, 102, 103]
    sports = ['Basketball', 'Soccer', 'Tennis']
    
    # Engagement scores (from the database schema)
    game_engagement_scores = {
        (1, 101): 1.8,
        (2, 102): 2.2,
        (3, 103): 1.5
    }
    
    sport_engagement_scores = {
        (1, 'Basketball'): 1.5,
        (2, 'Soccer'): 1.8,
        (3, 'Tennis'): 2.0
    }
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(game_engagement_scores) == len(sport_engagement_scores) == len(students), "Array length mismatch"
    safe_range_students = range(len(students))
    
    # 2. VARIABLES
    x = {(stu, game): mdl.continuous_var(name=f"x_{stu}_{game}", lb=0) for stu in students for game in games}
    y = {(stu, sport): mdl.continuous_var(name=f"y_{stu}_{sport}", lb=0) for stu in students for sport in sports}
    
    # 3. OBJECTIVE FUNCTION
    objective = mdl.sum(game_engagement_scores[(stu, game)] * x[(stu, game)] for stu, game in game_engagement_scores) + \
                mdl.sum(sport_engagement_scores[(stu, sport)] * y[(stu, sport)] for stu, sport in sport_engagement_scores)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    # Total Hours Constraint
    for stu in students:
        mdl.add_constraint(
            mdl.sum(x[(stu, game)] for game in games) + mdl.sum(y[(stu, sport)] for sport in sports) <= 20,
            ctname=f"total_hours_{stu}"
        )
    
    # Scholarship Sports Hours Constraint (assuming all students are on scholarship for simplicity)
    for stu in students:
        mdl.add_constraint(
            mdl.sum(y[(stu, sport)] for sport in sports) >= 5,
            ctname=f"scholarship_hours_{stu}"
        )
    
    # Maximum Gaming Hours Constraint
    for stu in students:
        mdl.add_constraint(
            mdl.sum(x[(stu, game)] for game in games) <= 15,
            ctname=f"max_gaming_hours_{stu}"
        )
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for stu in students:
            for game in games:
                value = solution.get_value(x[(stu, game)])
                if value > 1e-6:
                    print(f"x[{stu}, {game}] = {value:.3f}")
            for sport in sports:
                value = solution.get_value(y[(stu, sport)])
                if value > 1e-6:
                    print(f"y[{stu}, {sport}] = {value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

    return mdl

# Run the optimization
optimize_student_engagement()