# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_real_estate_properties():
    """Optimize the selection of real estate properties for sale to maximize profit."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("real_estate_properties")
    
    # Data from the problem context
    agreed_selling_prices = [120000.0, 180000.0, 250000.0, 95000.0, 130000.0]
    vendor_requested_prices = [110000.0, 170000.0, 240000.0, 90000.0, 125000.0]
    room_counts = [3, 4, 5, 2, 3]
    features = ['desired_feature', 'other_feature', 'desired_feature', 'desired_feature', 'other_feature']
    
    # Constraint bounds
    max_properties_to_sell = 3
    max_total_rooms = 12
    min_desired_features = 2
    
    n_properties = len(agreed_selling_prices)
    
    # CRITICAL: Validate array lengths before loops
    assert len(agreed_selling_prices) == len(vendor_requested_prices) == len(room_counts) == len(features) == n_properties, "Array length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.BINARY, name=f"x_{i}") for i in range(n_properties)}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum((agreed_selling_prices[i] - vendor_requested_prices[i]) * x[i] for i in range(n_properties)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Maximum number of properties to sell
    model.addConstr(gp.quicksum(x[i] for i in range(n_properties)) <= max_properties_to_sell, name="max_properties_to_sell")
    
    # Maximum total number of rooms
    model.addConstr(gp.quicksum(room_counts[i] * x[i] for i in range(n_properties)) <= max_total_rooms, name="max_total_rooms")
    
    # Minimum number of properties with desired feature
    desired_feature_indices = [i for i in range(n_properties) if features[i] == 'desired_feature']
    model.addConstr(gp.quicksum(x[i] for i in desired_feature_indices) >= min_desired_features, name="min_desired_features")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_properties):
            if x[i].x > 1e-6:
                print(f"Property {i+1} selected: x[{i}] = {x[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
optimize_real_estate_properties()