# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_flight_schedule():
    """Optimize flight schedule to minimize operational costs."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("flight_2")
    
    # Data from the database
    flight_costs = {
        'FL123': 1200.0,
        'FL456': 2500.0,
        'FL789': 1800.0
    }
    
    mandatory_flights = {'FL789', 'FL101', 'FL202'}
    
    # Parameters
    max_flights = 5
    max_departures = {'AirportA': 3, 'AirportB': 2}
    max_arrivals = {'AirportA': 3, 'AirportB': 2}
    
    # Flights departing and arriving at each airport
    departures_from = {
        'AirportA': ['FL123', 'FL456'],
        'AirportB': ['FL789']
    }
    
    arrivals_at = {
        'AirportA': ['FL789'],
        'AirportB': ['FL123', 'FL456']
    }
    
    # Validate data lengths
    assert len(flight_costs) > 0, "No flight cost data available"
    
    # 2. VARIABLES
    x = {flight: model.addVar(vtype=GRB.BINARY, name=f"x_{flight}") 
         for flight in flight_costs}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(flight_costs[flight] * x[flight] for flight in flight_costs), GRB.MINIMIZE)
    
    # 4. CONSTRAINTS
    
    # Maximum number of flights operated
    model.addConstr(gp.quicksum(x[flight] for flight in flight_costs) <= max_flights, name="max_flights")
    
    # Mandatory flights
    for flight in mandatory_flights:
        if flight in x:
            model.addConstr(x[flight] == 1, name=f"mandatory_{flight}")
    
    # Maximum departures from each airport
    for airport, flights in departures_from.items():
        model.addConstr(gp.quicksum(x[flight] for flight in flights) <= max_departures[airport], name=f"max_departures_{airport}")
    
    # Maximum arrivals at each airport
    for airport, flights in arrivals_at.items():
        model.addConstr(gp.quicksum(x[flight] for flight in flights) <= max_arrivals[airport], name=f"max_arrivals_{airport}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for flight in flight_costs:
            if x[flight].x > 1e-6:
                print(f"Flight {flight} is operated.")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_flight_schedule()