# Complete DOCPLEX implementation

from docplex.mp.model import Model

def sports_competition_optimization():
    """Optimization for assigning players to clubs to maximize total points."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="sports_competition")
    
    # Data from the problem context
    players = [
        {"PlayerID": 1, "Points": 15, "MaxApps": 3},
        {"PlayerID": 2, "Points": 25, "MaxApps": 4},
        {"PlayerID": 3, "Points": 10, "MaxApps": 2}
    ]
    
    clubs = [
        {"ClubID": 1, "Capacity": 5},
        {"ClubID": 2, "Capacity": 10},
        {"ClubID": 3, "Capacity": 8}
    ]
    
    # Extracting data into lists for easier handling
    player_ids = [p["PlayerID"] for p in players]
    player_points = [p["Points"] for p in players]
    player_max_apps = [p["MaxApps"] for p in players]
    
    club_ids = [c["ClubID"] for c in clubs]
    club_capacities = [c["Capacity"] for c in clubs]
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(player_ids) == len(player_points) == len(player_max_apps), "Player data length mismatch"
    assert len(club_ids) == len(club_capacities), "Club data length mismatch"
    
    safe_player_range = range(len(player_ids))
    safe_club_range = range(len(club_ids))
    
    # 2. VARIABLES
    # Binary decision variables for player-club assignments
    x = {(i, j): mdl.binary_var(name=f"x_{i}_{j}") for i in safe_player_range for j in safe_club_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total points scored by all clubs
    objective = mdl.sum(player_points[i] * x[i, j] for i in safe_player_range for j in safe_club_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Player Application Limit
    for i in safe_player_range:
        mdl.add_constraint(mdl.sum(x[i, j] for j in safe_club_range) <= player_max_apps[i], ctname=f"player_app_limit_{i}")
    
    # Club Capacity Limit
    for j in safe_club_range:
        mdl.add_constraint(mdl.sum(x[i, j] for i in safe_player_range) <= club_capacities[j], ctname=f"club_capacity_{j}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_player_range:
            for j in safe_club_range:
                value = solution.get_value(x[i, j])
                if value > 1e-6:
                    print(f"Player {player_ids[i]} assigned to Club {club_ids[j]}: {value}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
sports_competition_optimization()