# Complete DOCPLEX implementation

from docplex.mp.model import Model

def machine_repair_optimization():
    """Optimize technician assignments to minimize total value points of machine repairs."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="machine_repair")
    
    # Data from the problem context
    machine_ids = [1, 2, 3]
    value_points = [15, 25, 10]
    technician_ids = [1, 2, 3]
    max_repairs = [3, 2, 1]
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(machine_ids) == len(value_points), "Machine data length mismatch"
    assert len(technician_ids) == len(max_repairs), "Technician data length mismatch"
    
    # Safe indexing
    safe_machine_range = range(len(machine_ids))
    safe_technician_range = range(len(technician_ids))
    
    # 2. VARIABLES
    # Binary decision variables for technician assignments
    x = {(i, j): mdl.binary_var(name=f"x_{i}_{j}") for i in safe_technician_range for j in safe_machine_range}
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the total value points of machines assigned to technicians
    objective = mdl.sum(value_points[j] * x[i, j] for i in safe_technician_range for j in safe_machine_range)
    mdl.minimize(objective)
    
    # 4. CONSTRAINTS
    
    # Each repair must be assigned to exactly one technician
    for j in safe_machine_range:
        mdl.add_constraint(mdl.sum(x[i, j] for i in safe_technician_range) == 1, ctname=f"repair_assignment_{j}")
    
    # Technician capacity constraints
    for i in safe_technician_range:
        mdl.add_constraint(mdl.sum(x[i, j] for j in safe_machine_range) <= max_repairs[i], ctname=f"capacity_{i}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_technician_range:
            for j in safe_machine_range:
                if solution.get_value(x[i, j]) > 1e-6:
                    print(f"Technician {technician_ids[i]} assigned to machine {machine_ids[j]}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

    return mdl

# Run the optimization
machine_repair_optimization()