# Complete DOCPLEX implementation

from docplex.mp.model import Model

def optimize_party_host_assignment():
    """Optimize host assignments to parties using DOCplex"""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="party_host_assignment")
    
    # Example data setup
    parties = [1, 2, 3]  # Party IDs
    hosts = [101, 102, 103, 104, 105]  # Host IDs
    max_hosts_per_party = 2  # Maximum number of hosts allowed per party
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(parties) > 0 and len(hosts) > 0, "Parties or hosts list is empty"
    
    # 2. VARIABLES
    # Binary decision variables for host assignments
    x = {(i, j): mdl.binary_var(name=f"x_{i}_{j}") for i in parties for j in hosts}
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the total number of host assignments
    objective = mdl.sum(x[i, j] for i in parties for j in hosts)
    mdl.minimize(objective)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Each party must have at least one host
    for i in parties:
        mdl.add_constraint(mdl.sum(x[i, j] for j in hosts) >= 1, ctname=f"min_hosts_{i}")
    
    # No party should exceed the maximum number of hosts allowed
    for i in parties:
        mdl.add_constraint(mdl.sum(x[i, j] for j in hosts) <= max_hosts_per_party, ctname=f"max_hosts_{i}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in parties:
            for j in hosts:
                if solution.get_value(x[i, j]) > 1e-6:
                    print(f"Host {j} is assigned to Party {i}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
optimize_party_host_assignment()