# app/services/order_assignment_service.py

from app import crud
from app.assignment.distributor import OrderDistributor
from app.assignment.utils import get_field, set_field, split_item


def assign_waiters_to_order(db, order_products, algorithm: str = "least-loaded"):
    # --- load domain data ---
    waiters = crud.get_waiters(db)
    products = crud.get_products(db)
    last_order_waiters = crud.get_last_order_waiters(db)
    
    waiter_by_name = {w.name: w for w in waiters}
    product_by_id = {p.id: p for p in products}
    product_by_name = {p.name: p for p in products}

    # --- build product costs ---
    product_costs = {}
    for p in products:
        group = p.group.name if p.group else "Otros"
        product_costs.setdefault(group, {})[p.name] = p.cost

    # --- build order dict ---
    order_dict = {}
    for op in order_products:
        product = product_by_id.get(get_field(op, "product_id"))
        if product:
            order_dict[product.name] = (
                order_dict.get(product.name, 0) + get_field(op, "quantity", 0)
            )

    # --- distribute ---
    distributor = OrderDistributor(
        product_costs=product_costs,
        waiters=list(waiter_by_name.keys()),
    )
    distributor.waiter_load = {w.name: w.load for w in waiters}
    #distribution = distributor.distribute_single_order(order_dict)
    distribution, waiter_loads = distributor.distribute_single_order(algorithm, order_dict, last_order_waiters=last_order_waiters)
    #distribution = {
    #    "Cerveza": {"Alice": 2, "Bob": 1},, las
    #    "Pizza": {"Alice": 1},
    #}


    # --- apply distribution ---
    ops = list(order_products)

    for product_name, waiter_map in distribution.items():
        product = product_by_name[product_name]

        for waiter_name, qty in waiter_map.items():
            waiter = waiter_by_name[waiter_name]
            remaining = qty
            i = 0
            while i < len(ops) and remaining > 0:
                op = ops[i]
                if get_field(op, "product_id") != product.id:
                    i += 1
                    continue

                available = get_field(op, "quantity", 0)
                assign_qty = min(available, remaining)
                assigned = split_item(ops, i, assign_qty, waiter.id)
                if assigned:
                    ops.append(assigned)
                remaining -= assign_qty
                i += 1
    
    for w in waiters:
        w.load = waiter_loads[w.name]
        db.add(w)


    db.flush()
    return ops
