# Complete PYOMO implementation - Retry Attempt 4

import pyomo.environ as pyo
from pyomo.opt import SolverFactory

def product_catalog_optimization():
    """Optimize product pricing strategy to maximize revenue."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Exchange rates
    r_de = 1.18  # Example exchange rate from dollars to euros
    r_dp = 1.33  # Example exchange rate from dollars to pounds
    
    # Data from the database
    prices_dollars = [12.99, 18.49, 25.0]
    prices_euros = [11.04, 15.72, 21.25]
    prices_pounds = [9.74, 13.87, 18.75]
    min_prices_dollars = [11.99, 16.99, 22.5]
    min_prices_euros = [10.19, 14.44, 19.13]
    min_prices_pounds = [8.99, 12.74, 16.88]
    sales_volumes = [120, 180, 90]
    stock_availabilities = [150, 200, 100]
    
    # Validate array lengths
    n_products = len(prices_dollars)
    assert all(len(lst) == n_products for lst in [
        prices_euros, prices_pounds, min_prices_dollars, 
        min_prices_euros, min_prices_pounds, sales_volumes, stock_availabilities
    ]), "Array length mismatch"
    
    # 3. SETS
    model.I = pyo.RangeSet(1, n_products)
    
    # 4. PARAMETERS
    model.price_dollars = pyo.Param(model.I, initialize={i+1: prices_dollars[i] for i in range(n_products)})
    model.price_euros = pyo.Param(model.I, initialize={i+1: prices_euros[i] for i in range(n_products)})
    model.price_pounds = pyo.Param(model.I, initialize={i+1: prices_pounds[i] for i in range(n_products)})
    model.min_price_dollars = pyo.Param(model.I, initialize={i+1: min_prices_dollars[i] for i in range(n_products)})
    model.min_price_euros = pyo.Param(model.I, initialize={i+1: min_prices_euros[i] for i in range(n_products)})
    model.min_price_pounds = pyo.Param(model.I, initialize={i+1: min_prices_pounds[i] for i in range(n_products)})
    model.sales_volume = pyo.Param(model.I, initialize={i+1: sales_volumes[i] for i in range(n_products)})
    model.stock_available = pyo.Param(model.I, initialize={i+1: stock_availabilities[i] for i in range(n_products)})
    
    # 5. VARIABLES
    model.p_d = pyo.Var(model.I, within=pyo.NonNegativeReals)
    model.p_e = pyo.Var(model.I, within=pyo.NonNegativeReals)
    model.p_p = pyo.Var(model.I, within=pyo.NonNegativeReals)
    
    # 6. OBJECTIVE FUNCTION
    def revenue_rule(model):
        return sum(
            model.p_d[i] * model.sales_volume[i] +
            model.p_e[i] / r_de * model.sales_volume[i] +
            model.p_p[i] / r_dp * model.sales_volume[i]
            for i in model.I
        )
    model.revenue = pyo.Objective(rule=revenue_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    def min_price_dollars_rule(model, i):
        return model.p_d[i] >= model.min_price_dollars[i]
    model.min_price_dollars_constraint = pyo.Constraint(model.I, rule=min_price_dollars_rule)
    
    def min_price_euros_rule(model, i):
        return model.p_e[i] >= model.min_price_euros[i]
    model.min_price_euros_constraint = pyo.Constraint(model.I, rule=min_price_euros_rule)
    
    def min_price_pounds_rule(model, i):
        return model.p_p[i] >= model.min_price_pounds[i]
    model.min_price_pounds_constraint = pyo.Constraint(model.I, rule=min_price_pounds_rule)
    
    def stock_availability_rule(model, i):
        return model.sales_volume[i] <= model.stock_available[i]
    model.stock_availability_constraint = pyo.Constraint(model.I, rule=stock_availability_rule)
    
    def price_consistency_euros_rule(model, i):
        return model.p_e[i] == model.p_d[i] * r_de
    model.price_consistency_euros_constraint = pyo.Constraint(model.I, rule=price_consistency_euros_rule)
    
    def price_consistency_pounds_rule(model, i):
        return model.p_p[i] == model.p_d[i] * r_dp
    model.price_consistency_pounds_constraint = pyo.Constraint(model.I, rule=price_consistency_pounds_rule)
    
    # 8. SOLVING WITH GUROBI
    solver = SolverFactory('gurobi')
    results = solver.solve(model, tee=True)
    
    # 9. RESULT PROCESSING
    if results.solver.termination_condition == pyo.TerminationCondition.optimal:
        print("Optimal solution found!")
        print(f"Optimal value: {pyo.value(model.revenue)}")
        
        # Extract variable values
        print("\nVariable values:")
        for i in model.I:
            p_d_val = pyo.value(model.p_d[i])
            p_e_val = pyo.value(model.p_e[i])
            p_p_val = pyo.value(model.p_p[i])
            print(f"Product {i}: p_d = {p_d_val:.2f}, p_e = {p_e_val:.2f}, p_p = {p_p_val:.2f}")
        
    elif results.solver.termination_condition == pyo.TerminationCondition.infeasible:
        print("Problem is infeasible")
    elif results.solver.termination_condition == pyo.TerminationCondition.unbounded:
        print("Problem is unbounded")
    else:
        print(f"Solver terminated with condition: {results.solver.termination_condition}")

# Run the optimization
product_catalog_optimization()