# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_pilot_assignment():
    """Optimize the assignment of pilots to aircraft to minimize total flights."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("pilot_record")
    
    # Data from the database
    pilots = [1, 2, 3]
    aircrafts = [101, 102, 103]
    
    # Minimum flights required for each pilot
    min_flights = {1: 10, 2: 15, 3: 12}
    
    # Maximum flights allowed for each aircraft
    max_flights = {101: 120, 102: 100, 103: 110}
    
    # Validate data lengths
    assert len(min_flights) == len(pilots), "Mismatch in pilots and min_flights data"
    assert len(max_flights) == len(aircrafts), "Mismatch in aircrafts and max_flights data"
    
    # 2. VARIABLES
    # Decision variables: number of flights assigned to each pilot for each aircraft
    x = model.addVars(pilots, aircrafts, vtype=GRB.INTEGER, name="x", lb=0)
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the total number of flights assigned
    model.setObjective(gp.quicksum(x[i, j] for i in pilots for j in aircrafts), GRB.MINIMIZE)
    
    # 4. CONSTRAINTS
    # Pilot minimum flight requirement
    model.addConstrs((gp.quicksum(x[i, j] for j in aircrafts) >= min_flights[i] for i in pilots), name="pilot_min_flights")
    
    # Aircraft maximum flight capacity
    model.addConstrs((gp.quicksum(x[i, j] for i in pilots) <= max_flights[j] for j in aircrafts), name="aircraft_max_flights")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in pilots:
            for j in aircrafts:
                if x[i, j].x > 1e-6:
                    print(f"x[{i},{j}] = {x[i, j].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_pilot_assignment()