# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_match_allocation():
    """Optimize match allocation to maximize GDP impact."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("city_record")
    
    # Data: Cities, GDP, and Temperature suitability
    cities = [1, 2, 3]
    gdp = {1: 1500.0, 2: 2500.0, 3: 1800.0}
    temperature_suitability = {
        (1, 'Jan'): (16.0, 24.0),
        (2, 'Jan'): (18.0, 26.0),
        (3, 'Jan'): (15.0, 23.0),
        (1, 'Feb'): (17.0, 25.0),
        (2, 'Feb'): (19.0, 27.0),
        (3, 'Feb'): (16.0, 24.0),
        (1, 'Mar'): (18.0, 26.0),
        (2, 'Mar'): (20.0, 28.0),
        (3, 'Mar'): (17.0, 25.0)
    }
    
    matches = [1, 2, 3]
    months = ['Jan', 'Feb', 'Mar']
    
    # CRITICAL: Validate array lengths before loops
    assert len(cities) == len(gdp), "Array length mismatch for cities and GDP"
    
    # 2. VARIABLES
    x = model.addVars(matches, cities, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(gdp[c] * x[m, c] for m in matches for c in cities), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Each match is allocated to at most one city
    model.addConstrs((gp.quicksum(x[m, c] for c in cities) <= 1 for m in matches), name="match_allocation")
    
    # Temperature suitability constraint
    for m in matches:
        for c in cities:
            for month in months:
                min_temp, max_temp = temperature_suitability[(c, month)]
                if min_temp < 15 or max_temp > 27:
                    model.addConstr(x[m, c] == 0, name=f"temp_suitability_{m}_{c}_{month}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for m in matches:
            for c in cities:
                if x[m, c].x > 1e-6:
                    print(f"Match {m} allocated to City {c}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_match_allocation()