# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_cinema_schedule():
    """Optimize cinema film scheduling to maximize revenue"""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("cinema_schedule")
    
    # Data from the database
    cinema_data = [
        {"Cinema_ID": 1, "Capacity": 120, "Max_Screenings_Per_Day": 5},
        {"Cinema_ID": 2, "Capacity": 180, "Max_Screenings_Per_Day": 6},
        {"Cinema_ID": 3, "Capacity": 250, "Max_Screenings_Per_Day": 7}
    ]
    
    film_pricing_data = [
        {"Cinema_ID_Film_ID": 101, "Price": 12.0},
        {"Cinema_ID_Film_ID": 102, "Price": 15.0},
        {"Cinema_ID_Film_ID": 103, "Price": 10.0}
    ]
    
    avg_attendance = {
        101: 100,  # Example average attendance for film 101
        102: 150,  # Example average attendance for film 102
        103: 200   # Example average attendance for film 103
    }
    
    # Validate data lengths
    assert len(cinema_data) == 3, "Cinema data length mismatch"
    assert len(film_pricing_data) == 3, "Film pricing data length mismatch"
    
    # 2. VARIABLES
    # Decision variables: number of screenings for each film in each cinema
    x = {}
    for cinema in cinema_data:
        for film in film_pricing_data:
            x[(cinema["Cinema_ID"], film["Cinema_ID_Film_ID"])] = model.addVar(
                vtype=GRB.INTEGER, name=f"x_{cinema['Cinema_ID']}_{film['Cinema_ID_Film_ID']}", lb=0
            )
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total revenue
    model.setObjective(
        gp.quicksum(
            film["Price"] * x[(cinema["Cinema_ID"], film["Cinema_ID_Film_ID"])]
            for cinema in cinema_data
            for film in film_pricing_data
        ),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    # Maximum screenings per cinema
    for cinema in cinema_data:
        model.addConstr(
            gp.quicksum(
                x[(cinema["Cinema_ID"], film["Cinema_ID_Film_ID"])]
                for film in film_pricing_data
            ) <= cinema["Max_Screenings_Per_Day"],
            name=f"max_screenings_{cinema['Cinema_ID']}"
        )
    
    # Seating capacity constraint
    for cinema in cinema_data:
        for film in film_pricing_data:
            model.addConstr(
                avg_attendance[film["Cinema_ID_Film_ID"]] * x[(cinema["Cinema_ID"], film["Cinema_ID_Film_ID"])] <= cinema["Capacity"],
                name=f"capacity_{cinema['Cinema_ID']}_{film['Cinema_ID_Film_ID']}"
            )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for cinema in cinema_data:
            for film in film_pricing_data:
                var = x[(cinema["Cinema_ID"], film["Cinema_ID_Film_ID"])]
                if var.x > 1e-6:
                    print(f"x[{cinema['Cinema_ID']}, {film['Cinema_ID_Film_ID']}] = {var.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_cinema_schedule()