# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_customer_complaints():
    """Optimize the allocation of staff to manage customer complaints."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("customer_complaints")
    
    # Data from the database
    complaints = [
        {"complaint_id": 1, "resolution_time": 2},
        {"complaint_id": 2, "resolution_time": 3},
        {"complaint_id": 3, "resolution_time": 3}
    ]
    
    staff_capacity = [
        {"staff_id": 1, "max_complaints": 5},
        {"staff_id": 2, "max_complaints": 7},
        {"staff_id": 3, "max_complaints": 6}
    ]
    
    num_complaints = len(complaints)
    num_staff = len(staff_capacity)
    
    # CRITICAL: Validate array lengths before loops
    assert num_complaints > 0 and num_staff > 0, "No data available for complaints or staff"
    
    # 2. VARIABLES
    # Binary decision variables for complaint assignment
    x = model.addVars(num_complaints, num_staff, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    # Minimize total resolution time
    model.setObjective(
        gp.quicksum(complaints[i]["resolution_time"] * x[i, j] for i in range(num_complaints) for j in range(num_staff)),
        GRB.MINIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Each complaint must be assigned to exactly one staff member
    model.addConstrs(
        (gp.quicksum(x[i, j] for j in range(num_staff)) == 1 for i in range(num_complaints)),
        name="assign_complaint"
    )
    
    # The number of complaints assigned to each staff member must not exceed their capacity
    model.addConstrs(
        (gp.quicksum(x[i, j] for i in range(num_complaints)) <= staff_capacity[j]["max_complaints"] for j in range(num_staff)),
        name="staff_capacity"
    )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(num_complaints):
            for j in range(num_staff):
                if x[i, j].x > 1e-6:
                    print(f"Complaint {complaints[i]['complaint_id']} assigned to Staff {staff_capacity[j]['staff_id']}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_customer_complaints()