#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Store Product Allocation Optimization
"""

import gurobipy as gp
from gurobipy import GRB

def optimize_store_product_allocation():
    """Optimize product allocation across stores to maximize sales revenue."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("store_product_allocation")
    
    # Example data (replace with actual data loading from database)
    stores = [1, 2, 3]
    products = [101, 102, 103]
    
    sales_potential = {
        (1, 101): 50.0,
        (1, 102): 75.0,
        (1, 103): 100.0,
        (2, 101): 60.0,
        (2, 102): 80.0,
        (2, 103): 90.0,
        (3, 101): 70.0,
        (3, 102): 85.0,
        (3, 103): 95.0
    }
    
    product_availability = {
        101: 500,
        102: 750,
        103: 1000
    }
    
    store_capacity = {
        1: 1000,
        2: 1500,
        3: 2000
    }
    
    # CRITICAL: Validate array lengths before loops
    assert len(stores) > 0 and len(products) > 0, "Stores or products list is empty"
    
    # 2. VARIABLES
    x = model.addVars(stores, products, vtype=GRB.INTEGER, name="x", lb=10, ub=100)
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(
        gp.quicksum(sales_potential[s, p] * x[s, p] for s in stores for p in products),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Store Capacity Constraint
    for s in stores:
        model.addConstr(
            gp.quicksum(x[s, p] for p in products) <= store_capacity[s],
            name=f"store_capacity_{s}"
        )
    
    # Product Availability Constraint
    for p in products:
        model.addConstr(
            gp.quicksum(x[s, p] for s in stores) <= product_availability[p],
            name=f"product_availability_{p}"
        )
    
    # Minimum and Maximum Allocation Thresholds are handled by variable bounds
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for s in stores:
            for p in products:
                if x[s, p].x > 1e-6:
                    print(f"Allocation to store {s} for product {p}: {x[s, p].x:.0f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_store_product_allocation()