# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def election_optimization():
    """Optimize resource allocation for maximizing votes in an election"""

    # 1. MODEL & DATA SETUP
    model = gp.Model("election_optimization")

    # Data: Coefficients and constraints
    counties = [1, 2, 3]
    votes_coefficient = {1: 0.6, 2: 1.5, 3: 0.9}
    total_budget = 3000
    min_allocation = {1: 500, 2: 1000, 3: 600}
    max_allocation = {1: 1000, 2: 2000, 3: 1200}

    # CRITICAL: Validate array lengths before loops
    assert len(votes_coefficient) == len(min_allocation) == len(max_allocation) == len(counties), "Array length mismatch"

    # 2. VARIABLES
    # Variable dictionaries for resource allocation
    resource_allocation = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=0) for i in counties}

    # 3. OBJECTIVE FUNCTION
    # Maximize total expected votes
    model.setObjective(gp.quicksum(votes_coefficient[i] * resource_allocation[i] for i in counties), GRB.MAXIMIZE)

    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS

    # Total budget constraint
    model.addConstr(gp.quicksum(resource_allocation[i] for i in counties) <= total_budget, name="total_budget")

    # Minimum and maximum resource allocation constraints for each county
    for i in counties:
        model.addConstr(resource_allocation[i] >= min_allocation[i], name=f"min_allocation_{i}")
        model.addConstr(resource_allocation[i] <= max_allocation[i], name=f"max_allocation_{i}")

    # 5. SOLVING & RESULTS
    model.optimize()

    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in counties:
            if resource_allocation[i].x > 1e-6:
                print(f"Resource allocation for county {i}: {resource_allocation[i].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")

    return model

# Run the optimization
election_optimization()