# Complete DOCPLEX implementation

from docplex.mp.model import Model

def cinema_optimization():
    """Optimize cinema film scheduling to maximize revenue"""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="cinema_optimization")
    
    # Data from the problem context
    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_schedule_data = [
        {"Cinema_ID_Film_ID": 101, "Show_Times": 3},
        {"Cinema_ID_Film_ID": 102, "Show_Times": 4},
        {"Cinema_ID_Film_ID": 103, "Show_Times": 2}
    ]
    
    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}
    ]
    
    # Assumed average attendance per screening
    avg_attendance = {
        101: 100,
        102: 150,
        103: 200
    }
    
    # Extracting data into lists for processing
    cinema_ids = [c["Cinema_ID"] for c in cinema_data]
    capacities = [c["Capacity"] for c in cinema_data]
    max_screenings = [c["Max_Screenings_Per_Day"] for c in cinema_data]
    
    film_ids = [f["Cinema_ID_Film_ID"] for f in film_schedule_data]
    prices = [p["Price"] for p in film_pricing_data]
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(cinema_ids) == len(capacities) == len(max_screenings), "Cinema data length mismatch"
    assert len(film_ids) == len(prices), "Film data length mismatch"
    
    safe_range_cinema = range(len(cinema_ids))
    safe_range_film = range(len(film_ids))
    
    # 2. VARIABLES
    x = {j: mdl.integer_var(name=f"x_{film_ids[j]}", lb=0) for j in safe_range_film}
    
    # 3. OBJECTIVE FUNCTION
    objective = mdl.sum(prices[j] * x[j] for j in safe_range_film)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    # Maximum screenings per cinema
    for i in safe_range_cinema:
        cinema_id = cinema_ids[i]
        mdl.add_constraint(
            mdl.sum(x[j] for j in safe_range_film if film_ids[j] // 100 == cinema_id) <= max_screenings[i],
            ctname=f"max_screenings_cinema_{cinema_id}"
        )
    
    # Seating capacity constraints
    for j in safe_range_film:
        cinema_id = film_ids[j] // 100
        avg_att = avg_attendance[film_ids[j]]
        capacity = next(c["Capacity"] for c in cinema_data if c["Cinema_ID"] == cinema_id)
        mdl.add_constraint(
            avg_att * x[j] <= capacity,
            ctname=f"capacity_constraint_{film_ids[j]}"
        )
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for j in safe_range_film:
            value = solution.get_value(x[j])
            if value > 1e-6:
                print(f"x[{film_ids[j]}] = {value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
cinema_optimization()