# Complete GUROBIPY implementation - Retry Attempt 2

import gurobipy as gp
from gurobipy import GRB

def storm_resource_allocation():
    # 1. MODEL & DATA SETUP
    model = gp.Model("storm_resource_allocation")
    
    # Data from the problem
    storms = [1, 2, 3]
    regions = [101, 102, 103]
    
    # Storm details
    storm_details = {
        1: {'storm_speed': 110, 'Damage_millions_USD': 15.5, 'Number_Deaths': 55},
        2: {'storm_speed': 90, 'Damage_millions_USD': 10.0, 'Number_Deaths': 40},
        3: {'storm_speed': 130, 'Damage_millions_USD': 20.0, 'Number_Deaths': 70}
    }
    
    # Allocation costs
    allocation_costs = {
        (1, 101): 5000,
        (1, 102): 4000,
        (2, 103): 6000
    }
    
    # Weights for the objective function
    w1 = 1  # Weight for damage
    w2 = 1  # Weight for loss of life
    
    # Budget constraint
    total_budget = 1500000
    
    # Maximum number of cities that can be affected
    max_cities_affected = 5
    
    # 2. VARIABLES
    is_allocated = model.addVars(storms, regions, vtype=GRB.BINARY, name="is_allocated")
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the weighted sum of damage and loss of life
    objective = gp.quicksum(
        w1 * storm_details[storm_id]['Damage_millions_USD'] + w2 * storm_details[storm_id]['Number_Deaths']
        for storm_id in storms
    )
    model.setObjective(objective, GRB.MINIMIZE)
    
    # 4. CONSTRAINTS
    
    # Budget Constraint
    model.addConstr(
        gp.quicksum(
            allocation_costs.get((storm_id, region_id), 0) * is_allocated[storm_id, region_id]
            for storm_id in storms for region_id in regions
        ) <= total_budget, name="budget_constraint"
    )
    
    # Speed Constraint
    for storm_id in storms:
        if storm_details[storm_id]['storm_speed'] > 120:
            model.addConstr(
                gp.quicksum(is_allocated[storm_id, region_id] for region_id in regions) == 0,
                name=f"speed_constraint_{storm_id}"
            )
    
    # Cities Affected Constraint
    model.addConstr(
        gp.quicksum(is_allocated[storm_id, region_id] for storm_id in storms for region_id in regions) <= max_cities_affected,
        name="cities_affected_constraint"
    )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for storm_id in storms:
            for region_id in regions:
                if is_allocated[storm_id, region_id].x > 0.5:
                    print(f"Resources allocated to storm {storm_id} in region {region_id}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the function
storm_resource_allocation()