#!/usr/bin/env python3
"""
Gurobipy Implementation for Performance Attendance Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_performance_attendance():
    """Optimize the number of pieces each member performs to maximize attendance."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("performance_attendance")
    
    # Data from the problem
    members = [1, 2, 3]
    performances = [1, 2, 3]
    
    # Attendance data
    attendance = {1: 200, 2: 150, 3: 100}
    
    # Member constraints
    max_pieces_member = {1: 5, 2: 4, 3: 3}
    
    # Performance constraints
    max_pieces_performance = {1: 10, 2: 8, 3: 6}
    
    # Validate array lengths
    assert len(members) == len(max_pieces_member), "Member data length mismatch"
    assert len(performances) == len(attendance) == len(max_pieces_performance), "Performance data length mismatch"
    
    # 2. VARIABLES
    x = {(m, p): model.addVar(vtype=GRB.INTEGER, name=f"x_{m}_{p}", lb=0) 
         for m in members for p in performances}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(
        gp.quicksum(attendance[p] * x[m, p] for m in members for p in performances), 
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Maximum Pieces per Member
    for m in members:
        model.addConstr(
            gp.quicksum(x[m, p] for p in performances) <= max_pieces_member[m], 
            name=f"max_pieces_member_{m}"
        )
    
    # Maximum Pieces per Performance
    for p in performances:
        model.addConstr(
            gp.quicksum(x[m, p] for m in members) <= max_pieces_performance[p], 
            name=f"max_pieces_performance_{p}"
        )
    
    # Minimum Pieces per Member
    for m in members:
        model.addConstr(
            gp.quicksum(x[m, p] for p in performances) >= 1, 
            name=f"min_pieces_member_{m}"
        )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for m in members:
            for p in performances:
                if x[m, p].x > 1e-6:
                    print(f"Member {m} performs {x[m, p].x:.0f} pieces in performance {p}")
    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__":
    optimize_performance_attendance()