# Complete DOCPLEX implementation - Retry Attempt 4

from docplex.mp.model import Model

def optimize_loan_allocation():
    # 1. MODEL & DATA SETUP
    mdl = Model(name="loan_optimization")
    
    # Data from the problem context
    customers = [
        {"cust_ID": 1, "credit_score": 720},
        {"cust_ID": 2, "credit_score": 680},
        {"cust_ID": 3, "credit_score": 750}
    ]
    
    loans = [
        {"loan_ID": 101, "amount": 30000, "branch_ID": 1},
        {"loan_ID": 102, "amount": 45000, "branch_ID": 2},
        {"loan_ID": 103, "amount": 25000, "branch_ID": 3},
        {"loan_ID": 104, "amount": 20000, "branch_ID": 1},
        {"loan_ID": 105, "amount": 35000, "branch_ID": 2}
    ]
    
    branch_loans = [
        {"branch_ID": 1, "min_loans": 120000},
        {"branch_ID": 2, "min_loans": 150000},
        {"branch_ID": 3, "min_loans": 100000}
    ]
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(customers) == 3, "Customer data length mismatch"
    assert len(loans) == 5, "Loan data length mismatch"
    assert len(branch_loans) == 3, "Branch loans data length mismatch"
    
    # Safe range for indexing
    safe_range_customers = range(len(customers))
    safe_range_loans = range(len(loans))
    safe_range_branches = range(len(branch_loans))
    
    # 2. VARIABLES
    x = {loan['loan_ID']: mdl.continuous_var(name=f"x_{loan['loan_ID']}", lb=0, ub=50000) for loan in loans}
    
    # 3. OBJECTIVE FUNCTION
    objective = mdl.sum(customers[i]['credit_score'] * x[loans[i]['loan_ID']] for i in safe_range_loans)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Total Budget Constraint
    total_loan_amount = mdl.sum(x[loan['loan_ID']] for loan in loans)
    mdl.add_constraint(total_loan_amount <= 1000000, ctname="total_budget")
    
    # Branch Minimum Loan Requirement
    for branch in branch_loans:
        branch_id = branch['branch_ID']
        min_loans = branch['min_loans']
        branch_loan_sum = mdl.sum(x[loan['loan_ID']] for loan in loans if loan['branch_ID'] == branch_id)
        mdl.add_constraint(branch_loan_sum >= min_loans, ctname=f"min_loans_branch_{branch_id}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for loan in loans:
            loan_id = loan['loan_ID']
            value = solution.get_value(x[loan_id])
            if value > 1e-6:
                print(f"x[{loan_id}] = {value:.2f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

# Run the optimization
optimize_loan_allocation()