#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Host City Selection Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def host_city_optimization():
    """Optimize the selection of host cities for matches"""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("host_city_selection")
    
    # City data
    cities = [1, 2, 3]
    population = {1: 800000, 2: 1200000, 3: 600000}
    gdp = {1: 75000.0, 2: 110000.0, 3: 60000.0}
    avg_temperature = {1: 22.0, 2: 26.0, 3: 20.0}
    hosting_cost = {1: 120000.0, 2: 180000.0, 3: 100000.0}
    
    # Objective coefficients
    weight_population = 0.4
    weight_gdp = 0.3
    weight_temperature = 0.3
    
    # Constraints
    max_matches_per_city = 2
    total_budget = 1000000.0
    total_matches_limit = 10
    
    # CRITICAL: Validate array lengths before loops
    assert len(cities) == len(population) == len(gdp) == len(avg_temperature) == len(hosting_cost), "Array length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.INTEGER, name=f"x_{i}", lb=0, ub=max_matches_per_city) for i in cities}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(
        gp.quicksum(
            (weight_population * population[i] + weight_gdp * gdp[i] + weight_temperature * avg_temperature[i]) * x[i]
            for i in cities
        ),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Total matches constraint
    model.addConstr(
        gp.quicksum(x[i] for i in cities) <= total_matches_limit,
        name="total_matches_constraint"
    )
    
    # Budget constraint
    model.addConstr(
        gp.quicksum(hosting_cost[i] * x[i] for i in cities) <= total_budget,
        name="budget_constraint"
    )
    
    # Maximum matches per city constraint
    for i in cities:
        model.addConstr(
            x[i] <= max_matches_per_city,
            name=f"max_matches_per_city_{i}"
        )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in cities:
            if x[i].x > 1e-6:
                print(f"Matches in city {i}: {x[i].x:.0f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

if __name__ == "__main__":
    host_city_optimization()