# Complete GUROBIPY implementation - Retry Attempt 4

import gurobipy as gp
from gurobipy import GRB

def employee_hire_evaluation():
    # 1. MODEL & DATA SETUP
    model = gp.Model("employee_hire_evaluation")
    
    # Data from the problem context
    employee_ids = [1, 2, 3]
    shop_ids = [101, 102, 103]
    bonuses = {1: 500.0, 2: 750.0, 3: 1000.0}
    min_employees = {101: 3, 102: 4, 103: 5}
    
    # Validate data lengths
    assert len(employee_ids) == len(bonuses), "Mismatch in employee data length"
    assert len(shop_ids) == len(min_employees), "Mismatch in shop data length"
    
    # 2. VARIABLES
    # Decision variables: x[i, j] = 1 if employee i is assigned to shop j
    x = model.addVars(employee_ids, shop_ids, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total bonuses
    model.setObjective(gp.quicksum(bonuses[i] * x[i, j] for i in employee_ids for j in shop_ids), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    # Each employee is assigned to exactly one shop
    model.addConstrs((gp.quicksum(x[i, j] for j in shop_ids) == 1 for i in employee_ids), name="employee_assignment")
    
    # Each shop meets its minimum staffing requirement
    model.addConstrs((gp.quicksum(x[i, j] for i in employee_ids) >= min_employees[j] for j in shop_ids), name="shop_staffing")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in employee_ids:
            for j in shop_ids:
                if x[i, j].x > 0.5:  # Binary variable, so check if it's 1
                    print(f"Employee {i} assigned to Shop {j}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    else:
        print("Optimization ended with status", model.status)

# Run the optimization
employee_hire_evaluation()