# Complete GUROBIPY implementation - Retry Attempt 4

import gurobipy as gp
from gurobipy import GRB

def optimize_player_allocation():
    # 1. MODEL & DATA SETUP
    model = gp.Model("player_allocation")

    # Sample data based on the provided schema
    players = [1, 2, 3]
    teams = [1, 2, 3]
    positions = [1, 2, 3]

    # Historical win rates for each player-position combination
    historical_win_rates = {
        (1, 1): 0.75,
        (2, 2): 0.8,
        (3, 3): 0.85
    }

    # Team constraints
    min_players = {1: 5, 2: 6, 3: 7}
    max_players = {1: 10, 2: 11, 3: 12}

    # League capacity
    capacity = 100

    # Validate array lengths before loops
    assert len(players) * len(teams) * len(positions) == len(historical_win_rates), "Historical win rates mismatch"

    # 2. VARIABLES
    # Decision variable: x[p, t] = 1 if player p is assigned to team t, 0 otherwise
    x = model.addVars(players, teams, vtype=GRB.BINARY, name="x")

    # 3. OBJECTIVE FUNCTION
    # Maximize the total wins across all teams
    model.setObjective(
        gp.quicksum(historical_win_rates.get((p, pos), 0) * x[p, t] for p in players for t in teams for pos in positions),
        GRB.MAXIMIZE
    )

    # 4. CONSTRAINTS

    # Player Assignment Constraint: Each player can be assigned to at most one team
    for p in players:
        model.addConstr(
            gp.quicksum(x[p, t] for t in teams) <= 1,
            name=f"player_assignment_{p}"
        )

    # Team Size Constraints: Each team must have at least the minimum number of players and no more than the maximum number of players
    for t in teams:
        model.addConstr(
            gp.quicksum(x[p, t] for p in players) >= min_players[t],
            name=f"min_players_{t}"
        )
        model.addConstr(
            gp.quicksum(x[p, t] for p in players) <= max_players[t],
            name=f"max_players_{t}"
        )

    # League Capacity Constraint: The total number of players assigned across all teams cannot exceed the league's capacity
    model.addConstr(
        gp.quicksum(x[p, t] for p in players for t in teams) <= capacity,
        name="league_capacity"
    )

    # 5. SOLVING & RESULTS
    model.optimize()

    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for p in players:
            for t in teams:
                if x[p, t].x > 1e-6:
                    print(f"Player {p} assigned to Team {t}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")

    return model

# Execute the optimization
optimize_player_allocation()