"""
PATH A GOLDEN STANDARD — Inbound shipment landed-cost computation.

For any inbound shipment with:
- A supplier PR with line items at NET (post-discount) supplier rates
  (rates derived from invoice Amount / Qty, NOT the displayed price column)
- Some "Omaggio" / free units the supplier billed at $0
- Customs/duty/freight charges to capitalize as inbound landed cost
- Inbound 3PL handling charges (e.g. Flexport prep+inbounding+receipt-storage)

This script computes:
  1. Distribute-by-Amount per-item shares for each "regular" charge LCV
     (e.g., the customs+freight invoice = LCV-A, the Flexport-inbound LCV = LCV-B)
  2. The fair-value charge target each item should land on (sample at LIST price
     for fair value, not at $0)
  3. The Path A redistribution LCV per-item applicable_charges
     = fair-value target − (LCV-A share + LCV-B share). Sums to $0 exactly.
  4. Final per-item landed values + valuation_rate.

Invariants:
- Sum of LCV-A per-item allocations = LCV-A.total
- Sum of LCV-B per-item allocations = LCV-B.total
- Sum of Path A per-item allocations = $0 (zero-net redistribution)
- Sum (book + sum_LCV_charges) = supplier_net_pay + LCV-A.total + LCV-B.total
- Sample's fair-value charge share = (sample_qty × list_price / total_fair_value) × total_charges
- Stock Coffee debit (or Stock Machines) = total landed value (perfect, no rounding residual)

Rounding strategy: per-item shares are round(2). Any rounding residual on each
LCV is applied to the LARGEST line in that LCV so the LCV total is exact.
This is what ERPNext's "Distribute by Amount" mode does internally.
"""
from decimal import Decimal, ROUND_HALF_UP

def round2(x):
    return float(Decimal(str(x)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))

def distribute_by_amount(total_charge, items_book):
    """items_book: list of (code, book_amount). Returns dict code → share."""
    PR_TOTAL = sum(amt for _, amt in items_book)
    shares = {code: round2(amt * total_charge / PR_TOTAL) if amt else 0.0
              for code, amt in items_book}
    residual = round2(total_charge - sum(shares.values()))
    if residual:
        # apply residual to largest item
        largest = max(shares, key=lambda k: shares[k])
        shares[largest] = round2(shares[largest] + residual)
    return shares

def distribute_by_fair_value(total_charge, items_fair):
    """items_fair: list of (code, fair_value). Returns dict code → share."""
    TOT_FAIR = sum(fv for _, fv in items_fair)
    shares = {code: round2(fv * total_charge / TOT_FAIR) if fv else 0.0
              for code, fv in items_fair}
    residual = round2(total_charge - sum(shares.values()))
    if residual:
        largest = max(shares, key=lambda k: shares[k])
        shares[largest] = round2(shares[largest] + residual)
    return shares

def path_a_lcv(items, lcv_a_share, lcv_b_share, total_charges, fair_values):
    """Compute Path A per-item applicable_charges for fair-value redistribution.
    Net sum is $0 by construction."""
    target = distribute_by_fair_value(total_charges, fair_values)
    pa = {}
    for code in [c for c, _ in items]:
        pa[code] = round2(target[code] - lcv_a_share.get(code, 0) - lcv_b_share.get(code, 0))
    # sanity: net should be 0; if not, fix the largest line
    net = round2(sum(pa.values()))
    if net != 0:
        largest = max(pa, key=lambda k: abs(pa[k]))
        pa[largest] = round2(pa[largest] - net)
    return pa, target

# === PASCUCCI MARCH 2026 COFFEE SHIPMENT (CONTAINER CICU6794096) ===
# Reference: invoice 2025-VA-0002522, Euro Cargo 1335680-01,
#            Flexport bills 642158 + 645137 (inbound-capitalize lines only)
COFFEE_ITEMS = [
    ('PUI-CAP-RISERVA-20',       2136, 4.21,  8992.56),  # (code, qty, fair_unit_list, book_amount)
    ('PUI-CAP-MORORA-20',        1308, 3.51,  4591.08),
    ('PUI-CAP-PLACIDO-20',       822,  4.91,  4036.02),
    ('PUI-CAP-ALTURA-20',        1374, 4.44,  6100.56),
    ('PUI-GND-ALTURA-70G',       1600, 1.315, 2104.00),
    ('PUI-INS-AMERICANO-12',     1008, 1.315, 1325.52),
    ('PUI-INS-AMERICANO-SAMPLE', 4995, 1.32,  0.00),     # Omaggio: book $0, fair $1.32 list
    ('PUI-CAP-SAMPLE-120',       700,  27.61, 19327.00),
    ('PUI-CAP-MAMA-20',          768,  4.44,  3409.92),
]

LCV_A_TOTAL = 9873.79  # Euro Cargo Coffee (duties + freight + brokerage)
LCV_B_TOTAL = 1626.00  # Flexport inbound-capitalize subset

if __name__ == '__main__':
    items_book = [(c, b) for c, q, fu, b in COFFEE_ITEMS]
    items_fair = [(c, q*fu) for c, q, fu, b in COFFEE_ITEMS]

    L_A = distribute_by_amount(LCV_A_TOTAL, items_book)
    L_B = distribute_by_amount(LCV_B_TOTAL, items_book)
    PathA, target = path_a_lcv(COFFEE_ITEMS, L_A, L_B, LCV_A_TOTAL+LCV_B_TOTAL, items_fair)

    print(f"{'Item':30s}{'Qty':>6s}{'Book':>10s}{'L_A':>9s}{'L_B':>9s}{'PathA':>10s}"
          f"{'Tot LCV':>10s}{'Landed':>11s}{'$/u':>10s}")
    total = 0.0
    for c, q, fu, b in COFFEE_ITEMS:
        tot_lcv = L_A[c] + L_B[c] + PathA[c]
        landed = b + tot_lcv
        total += landed
        print(f"{c:30s}{q:>6d}{b:>10.2f}{L_A[c]:>9.2f}{L_B[c]:>9.2f}{PathA[c]:>+10.2f}"
              f"{tot_lcv:>10.2f}{landed:>11.2f}{landed/q:>10.4f}")
    print(f"\n  Stock - Coffee TOTAL: ${total:.2f}")
    print(f"  Expected: ${sum(b for _,_,_,b in COFFEE_ITEMS) + LCV_A_TOTAL + LCV_B_TOTAL:.2f}")
