#!/usr/bin/env python3
"""
DOCPLEX implementation for bike-sharing optimization problem
"""

from docplex.mp.model import Model

def bike_sharing_optimization():
    # 1. MODEL & DATA SETUP
    mdl = Model(name="bike_sharing_optimization")
    
    # Data from the problem
    stations = [1, 2, 3]
    unmet_demands = {1: 2, 2: 0, 3: 1}
    dock_capacities = {1: 15, 2: 20, 3: 10}
    initial_bikes = {1: 10, 2: 15, 3: 8}  # Assumed initial bike counts
    cost_per_bike_movement = 3
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(stations) == len(unmet_demands) == len(dock_capacities) == len(initial_bikes), "Array length mismatch"
    safe_range = range(min(len(stations), len(unmet_demands), len(dock_capacities), len(initial_bikes)))  # Safe indexing
    
    # 2. VARIABLES
    # Decision variables for bike movements
    x = {(i, j): mdl.integer_var(name=f"x_{i}_{j}", lb=0) for i in stations for j in stations if i != j}
    
    # Decision variables for unmet demands
    u = {i: mdl.integer_var(name=f"u_{i}", lb=0) for i in stations}
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the total cost of bike movements and unmet demands
    movement_cost = mdl.sum(cost_per_bike_movement * x[(i, j)] for i in stations for j in stations if i != j)
    unmet_cost = mdl.sum(u[i] for i in stations)
    mdl.minimize(movement_cost + unmet_cost)
    
    # 4. CONSTRAINTS
    
    # Station Capacity Constraint
    for j in stations:
        mdl.add_constraint(mdl.sum(x[(i, j)] for i in stations if i != j) <= dock_capacities[j], ctname=f"capacity_{j}")
    
    # Initial Bike Availability Constraint
    for i in stations:
        mdl.add_constraint(mdl.sum(x[(i, j)] for j in stations if i != j) <= initial_bikes[i], ctname=f"initial_bikes_{i}")
    
    # Unmet Demand Constraint
    for i in stations:
        mdl.add_constraint(u[i] >= unmet_demands[i], ctname=f"unmet_demand_{i}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in stations:
            for j in stations:
                if i != j:
                    value = solution.get_value(x[(i, j)])
                    if value > 1e-6:
                        print(f"Bikes moved from station {i} to station {j}: {value:.0f}")
        for i in stations:
            value = solution.get_value(u[i])
            print(f"Unmet demand at station {i}: {value:.0f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

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