#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Cinema Scheduling Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def cinema_scheduling_optimization():
    """Optimize cinema scheduling to maximize revenue."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("cinema_scheduling")
    
    # Data from the database
    prices = [12.99, 9.99, 7.99]  # Price per showing for each film
    capacities = [150, 200, 100]  # Capacity of each cinema
    max_showings_per_day = 12     # Maximum showings per day per cinema
    min_showings_per_film = 1     # Minimum showings per film per cinema per day
    
    # Number of films and cinemas
    n_films = len(prices)
    n_cinemas = len(capacities)
    
    # CRITICAL: Validate array lengths before loops
    assert len(prices) == n_films, "Price array length mismatch"
    assert len(capacities) == n_cinemas, "Capacity array length mismatch"
    
    # 2. VARIABLES
    # Decision variable: x[f, c] = number of showings per day for film f in cinema c
    x = model.addVars(n_films, n_cinemas, vtype=GRB.INTEGER, name="x", lb=min_showings_per_film)
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total revenue: sum over films and cinemas of (Price_f * Capacity_c * x[f, c])
    model.setObjective(
        gp.quicksum(prices[f] * capacities[c] * x[f, c] for f in range(n_films) for c in range(n_cinemas)),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Constraint 1: Maximum showings per day per cinema
    for c in range(n_cinemas):
        model.addConstr(
            gp.quicksum(x[f, c] for f in range(n_films)) <= max_showings_per_day,
            name=f"max_showings_cinema_{c}"
        )
    
    # Constraint 2: Total capacity per day
    for c in range(n_cinemas):
        model.addConstr(
            gp.quicksum(capacities[c] * x[f, c] for f in range(n_films)) <= capacities[c] * max_showings_per_day,
            name=f"total_capacity_cinema_{c}"
        )
    
    # Constraint 3: Minimum showings per film per cinema per day (handled by variable lower bound)
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal:.2f}")
        for f in range(n_films):
            for c in range(n_cinemas):
                if x[f, c].x > 1e-6:
                    print(f"Film {f} in Cinema {c}: {x[f, c].x:.0f} showings")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
if __name__ == "__main__":
    cinema_scheduling_optimization()