# Complete DOCPLEX implementation

from docplex.mp.model import Model

def voter_optimization():
    """Optimization model for maximizing votes for contestants"""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="voter_optimization")
    
    # Example data setup
    contestants = [1, 2, 3]
    states = [1, 2, 3]
    
    # Maximum votes per contestant (example values)
    max_votes = {1: 300, 2: 295, 3: 305}
    
    # Minimum votes per contestant per state (example values)
    min_votes = {
        (1, 1): 50, (1, 2): 40, (1, 3): 30,
        (2, 1): 45, (2, 2): 35, (2, 3): 25,
        (3, 1): 55, (3, 2): 45, (3, 3): 35
    }
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(contestants) == len(max_votes), "Array length mismatch for contestants and max_votes"
    assert len(states) * len(contestants) == len(min_votes), "Array length mismatch for min_votes"
    
    # 2. VARIABLES
    # Variable dictionaries for votes
    votes = {(i, j): mdl.integer_var(name=f"x_{i}_{j}", lb=0) for i in contestants for j in states}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total votes
    objective = mdl.sum(votes[i, j] for i in contestants for j in states)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Maximum votes per contestant
    for i in contestants:
        mdl.add_constraint(mdl.sum(votes[i, j] for j in states) <= max_votes[i], ctname=f"max_votes_{i}")
    
    # Minimum votes per contestant per state
    for i in contestants:
        for j in states:
            mdl.add_constraint(votes[i, j] >= min_votes[i, j], ctname=f"min_votes_{i}_{j}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in contestants:
            for j in states:
                value = solution.get_value(votes[i, j])
                if value > 1e-6:
                    print(f"Votes for contestant {i} from state {j}: {value:.0f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
voter_optimization()