"""Push the ERP's master data to Slflo by the ERP's own keys, in the order references need.

  python3 push_master_data.py

Units → price list → products → sellable units → prices → customers → branches → balances.
A key named before it was pushed is 422 UNKNOWN_REFERENCE and nothing is written, so the order
matters. Run it as often as you like: what didn't change answers "unchanged" and costs nothing.
"""
import sys
import uuid
from datetime import datetime, timezone

from slflo import Slflo, TokenRefused, report

# What your ERP holds. In a real connector these come from your ERP's tables.
UNITS = {"PCS": {"en": "Piece", "ar": "قطعة"}, "CTN": {"en": "Carton", "ar": "كرتونة"}}
PRICE_LIST = ("RETAIL-EGP", {"name": {"en": "Retail", "ar": "تجزئة"}, "currency": "EGP"})
PRODUCTS = {
    "ITEM-1001": {"name": {"en": "Cola 330ml", "ar": "كولا ٣٣٠ مل"}, "pieces_per_carton": 24, "price": "10.00"},
    "ITEM-1002": {"name": {"en": "Water 1.5l", "ar": "مياه ١٫٥ لتر"}, "pieces_per_carton": 6, "price": "7.50"},
}
CUSTOMERS = {
    "CUST-1001": {"name": {"en": "Al Amal Market", "ar": "سوق الأمل"}, "address": "12 Tahrir St, Giza",
                  "credit_limit": 100000, "balance": 12500, "branches": {"02": "Dokki branch"}},
    "CUST-1002": {"name": {"en": "Delta Kiosk", "ar": "كشك الدلتا"}, "address": "4 Nile Corniche, Cairo",
                  "credit_limit": 50000, "balance": 0, "branches": {}},
}


# One key per call per run. The client's retries reuse it, so a lost answer is replayed, never
# applied twice; the next run uses new keys and so gets real answers ("unchanged").
RUN = uuid.uuid4().hex[:12]


def push(api, results, path, body, query=None):
    answer = api.put(path, body, key=f"md:{RUN}:{path}", query=query)["data"]
    results[path] = answer.get("result") or {k: answer[k] for k in ("written", "unchanged", "removed")}


# region push
def push_all(api):
    results = {}
    for ref, name in UNITS.items():
        push(api, results, f"/units/{ref}", {"name": name})

    list_ref, list_body = PRICE_LIST
    push(api, results, f"/price-lists/{list_ref}", list_body)

    for ref, item in PRODUCTS.items():
        push(api, results, f"/products/{ref}", {"name": item["name"], "base_unit_ref": "PCS", "active": True})
        push(api, results, f"/products/{ref}/units", {"units": [
            {"unit_ref": "PCS", "factor_to_base": 1, "order_default": True},
            {"unit_ref": "CTN", "factor_to_base": item["pieces_per_carton"], "order_default": False},
        ]})

    # The whole list in one call (at most 500 rows): replace removes the list's prices not in it.
    prices = []
    for ref, item in PRODUCTS.items():
        piece = float(item["price"])
        prices.append({"product_ref": ref, "unit_ref": "PCS", "price": piece, "valid_from": "2026-01-01"})
        prices.append({"product_ref": ref, "unit_ref": "CTN", "price": round(piece * item["pieces_per_carton"], 2),
                       "valid_from": "2026-01-01"})
    push(api, results, f"/price-lists/{list_ref}/prices", {"prices": prices}, query={"mode": "replace"})

    as_of = datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
    for ref, customer in CUSTOMERS.items():
        push(api, results, f"/customers/{ref}", {
            "name": customer["name"], "address": customer["address"], "blocked": False,
            "credit_limit": customer["credit_limit"], "price_list_ref": list_ref,
        })
        for branch_ref, branch_name in customer["branches"].items():
            push(api, results, f"/customers/{ref}/branches/{branch_ref}", {"name": {"en": branch_name}, "blocked": False})
        push(api, results, f"/customers/{ref}/balance", {
            "balance": customer["balance"], "credit_limit": customer["credit_limit"], "as_of": as_of,
        })
    return results
# endregion


def main():
    try:
        results = push_all(Slflo())
    except TokenRefused as stop:
        report({"stopped_by": stop.code})
        return 3
    for path, result in results.items():
        print(f"{path}: {result}", file=sys.stderr)
    report(results)
    return 0


if __name__ == "__main__":
    sys.exit(main())
