#!/usr/bin/env python3
"""
DOCplex 2.29.245 Implementation for Orchestra Optimization Problem
"""

from docplex.mp.model import Model

def orchestra_optimization():
    """Optimize the number of performances for each orchestra to maximize total attendance."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="orchestra_optimization")
    
    # Data from the problem
    orchestras = [1, 2, 3]
    attendance = {1: 500, 2: 600, 3: 450}
    min_performances = {1: 1, 2: 2, 3: 1}
    max_performances = {1: 10, 2: 12, 3: 8}
    total_conductor_availability = 300  # Sum of conductor availability
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(orchestras) == len(attendance) == len(min_performances) == len(max_performances), "Array length mismatch"
    safe_range = range(min(len(orchestras), len(attendance), len(min_performances), len(max_performances)))  # Safe indexing
    
    # 2. VARIABLES
    # Decision variables: number of performances for each orchestra
    x = {i: mdl.integer_var(name=f"x_{i}", lb=min_performances[i], ub=max_performances[i]) for i in orchestras}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total attendance
    objective = mdl.sum(attendance[i] * x[i] for i in orchestras)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Constraint 1: Total number of performances must not exceed conductor availability
    total_performances = mdl.sum(x[i] for i in orchestras)
    mdl.add_constraint(total_performances <= total_conductor_availability, ctname="conductor_availability")
    
    # Constraint 2: Each orchestra must conduct at least the minimum number of performances
    for i in orchestras:
        mdl.add_constraint(x[i] >= min_performances[i], ctname=f"min_performances_{i}")
    
    # Constraint 3: Each orchestra cannot conduct more than the maximum number of performances
    for i in orchestras:
        mdl.add_constraint(x[i] <= max_performances[i], ctname=f"max_performances_{i}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in orchestras:
            value = solution.get_value(x[i])
            print(f"x[{i}] = {value}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Execute the optimization
if __name__ == "__main__":
    orchestra_optimization()