#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Real Estate Properties Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_real_estate_properties():
    """Optimize the agreed selling price for real estate properties to maximize total revenue."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("real_estate_properties")
    
    # Data from the problem
    properties = {
        1: {"vendor_requested_price": 300000.0, "buyer_offered_price": 340000.0},
        2: {"vendor_requested_price": 450000.0, "buyer_offered_price": 500000.0},
        3: {"vendor_requested_price": 240000.0, "buyer_offered_price": 280000.0}
    }
    
    property_features = {
        1: [("Pool", 0.15), ("Garage", 0.1)],
        2: [("Garden", 0.2)],
        3: [("Garage", 0.1)]
    }
    
    weighting_factor = 0.3
    
    # CRITICAL: Validate array lengths before loops
    assert len(properties) == len(property_features), "Properties and features length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=0) for i in properties}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(x[i] for i in properties), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    for i in properties:
        vendor_price = properties[i]["vendor_requested_price"]
        buyer_price = properties[i]["buyer_offered_price"]
        
        # Vendor's Minimum Price Constraint
        model.addConstr(x[i] >= vendor_price, name=f"vendor_min_{i}")
        
        # Buyer's Maximum Price Constraint
        model.addConstr(x[i] <= buyer_price, name=f"buyer_max_{i}")
        
        # Feature-Adjusted Price Constraint
        feature_sum = sum(feature[1] for feature in property_features[i])
        adjusted_price = vendor_price * (1 + weighting_factor * feature_sum)
        model.addConstr(x[i] >= adjusted_price, name=f"feature_adjusted_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in properties:
            print(f"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()