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

import gurobipy as gp
from gurobipy import GRB

def optimize_product_pricing():
    """Optimize product pricing to maximize revenue while adhering to constraints."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("product_pricing_optimization")
    
    # Exchange rates and maximum price difference
    usd_to_eur = 0.92
    usd_to_gbp = 0.79
    eur_to_gbp = 0.86
    max_price_diff = 5.0
    
    # Product data
    product_ids = [1, 2, 3]
    sales_volume = {1: 150, 2: 200, 3: 100}
    price_constraints = {
        1: {'min_price_dollars': 10.0, 'max_price_dollars': 50.0,
            'min_price_euros': 9.0, 'max_price_euros': 45.0,
            'min_price_pounds': 8.0, 'max_price_pounds': 40.0},
        2: {'min_price_dollars': 15.0, 'max_price_dollars': 55.0,
            'min_price_euros': 14.0, 'max_price_euros': 50.0,
            'min_price_pounds': 13.0, 'max_price_pounds': 45.0},
        3: {'min_price_dollars': 20.0, 'max_price_dollars': 60.0,
            'min_price_euros': 19.0, 'max_price_euros': 55.0,
            'min_price_pounds': 18.0, 'max_price_pounds': 50.0}
    }
    
    # CRITICAL: Validate array lengths before loops
    assert len(product_ids) == len(sales_volume) == len(price_constraints), "Array length mismatch"
    
    # 2. VARIABLES
    # Decision variables for prices in each currency
    p_usd = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"p_usd_{i}", 
                             lb=price_constraints[i]['min_price_dollars'], 
                             ub=price_constraints[i]['max_price_dollars']) 
             for i in product_ids}
    
    p_eur = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"p_eur_{i}", 
                             lb=price_constraints[i]['min_price_euros'], 
                             ub=price_constraints[i]['max_price_euros']) 
             for i in product_ids}
    
    p_gbp = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"p_gbp_{i}", 
                             lb=price_constraints[i]['min_price_pounds'], 
                             ub=price_constraints[i]['max_price_pounds']) 
             for i in product_ids}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total revenue
    model.setObjective(
        gp.quicksum(sales_volume[i] * (p_usd[i] + p_eur[i] + p_gbp[i]) for i in product_ids),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Currency price differences
    for i in product_ids:
        # USD to EUR
        model.addConstr(
            usd_to_eur * p_usd[i] - p_eur[i] <= max_price_diff,
            name=f"usd_eur_diff_upper_{i}"
        )
        model.addConstr(
            p_eur[i] - usd_to_eur * p_usd[i] <= max_price_diff,
            name=f"usd_eur_diff_lower_{i}"
        )
        
        # USD to GBP
        model.addConstr(
            usd_to_gbp * p_usd[i] - p_gbp[i] <= max_price_diff,
            name=f"usd_gbp_diff_upper_{i}"
        )
        model.addConstr(
            p_gbp[i] - usd_to_gbp * p_usd[i] <= max_price_diff,
            name=f"usd_gbp_diff_lower_{i}"
        )
        
        # EUR to GBP
        model.addConstr(
            eur_to_gbp * p_eur[i] - p_gbp[i] <= max_price_diff,
            name=f"eur_gbp_diff_upper_{i}"
        )
        model.addConstr(
            p_gbp[i] - eur_to_gbp * p_eur[i] <= max_price_diff,
            name=f"eur_gbp_diff_lower_{i}"
        )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in product_ids:
            print(f"Product {i}:")
            print(f"  USD Price: {p_usd[i].x:.2f}")
            print(f"  EUR Price: {p_eur[i].x:.2f}")
            print(f"  GBP Price: {p_gbp[i].x:.2f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_product_pricing()