#!/usr/bin/env python3
"""
Gurobipy Implementation for Journal Committee Optimization Problem
"""

import gurobipy as gp
from gurobipy import GRB

def journal_committee_optimization():
    """Optimize editor assignments to maximize journal sales."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("journal_committee")
    
    # Data from the problem
    journals = [1, 2, 3]
    editors = [1, 2, 3]
    sales = {1: 1200.0, 2: 1800.0, 3: 900.0}
    max_workloads = {1: 4, 2: 3, 3: 5}
    
    # CRITICAL: Validate array lengths before loops
    assert len(journals) == len(sales), "Journal and sales length mismatch"
    assert len(editors) == len(max_workloads), "Editor and workload length mismatch"
    
    # 2. VARIABLES
    # Binary decision variables x_ej: 1 if editor e is assigned to journal j, 0 otherwise
    x = model.addVars(editors, journals, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total sales: sum over all e and j of sales_j * x_ej
    model.setObjective(gp.quicksum(sales[j] * x[e, j] for e in editors for j in journals), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Editor Workload Constraint: Each editor e cannot be assigned more journals than their max workload
    for e in editors:
        model.addConstr(gp.quicksum(x[e, j] for j in journals) <= max_workloads[e], name=f"workload_{e}")
    
    # Journal Assignment Constraint: Each journal j must be assigned at least one editor
    for j in journals:
        model.addConstr(gp.quicksum(x[e, j] for e in editors) >= 1, name=f"assignment_{j}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for e in editors:
            for j in journals:
                if x[e, j].x > 0.5:  # Check if x_ej is 1 (assigned)
                    print(f"Editor {e} assigned to Journal {j}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

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