#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Office Space Allocation Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_office_allocation():
    """Optimize the allocation of office spaces across multiple buildings to minimize total leasing cost."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("office_allocation")
    
    # Data from the problem
    buildings = [1, 2, 3]
    companies = [1, 2, 3]
    
    cost_per_sqft = {
        1: 55.0,
        2: 65.0,
        3: 45.0
    }
    
    required_space = {
        1: 1200,
        2: 1800,
        3: 900
    }
    
    available_space = {
        1: 6000,
        2: 7000,
        3: 5000
    }
    
    # CRITICAL: Validate array lengths before loops
    assert len(buildings) == len(cost_per_sqft) == len(available_space), "Building data length mismatch"
    assert len(companies) == len(required_space), "Company data length mismatch"
    
    # 2. VARIABLES
    # Decision variables: x_ij = space allocated to company i in building j
    x = model.addVars(companies, buildings, vtype=GRB.CONTINUOUS, name="x", lb=0)
    
    # 3. OBJECTIVE FUNCTION
    # Minimize total leasing cost
    model.setObjective(
        gp.quicksum(cost_per_sqft[j] * x[i, j] for i in companies for j in buildings),
        GRB.MINIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Minimum Space Requirement for each company
    for i in companies:
        model.addConstr(
            gp.quicksum(x[i, j] for j in buildings) >= required_space[i],
            name=f"min_space_company_{i}"
        )
    
    # Building Capacity for each building
    for j in buildings:
        model.addConstr(
            gp.quicksum(x[i, j] for i in companies) <= available_space[j],
            name=f"capacity_building_{j}"
        )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in companies:
            for j in buildings:
                if x[i, j].x > 1e-6:
                    print(f"Space allocated to company {i} in building {j}: {x[i, j].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the optimization
if __name__ == "__main__":
    optimize_office_allocation()