"""A nightly load: 1,000 products and 2,000 prices in 6 calls instead of 3,000.

  python3 push_prices_in_batches.py

POST /batch/products takes up to 500 items; PUT /price-lists/{ref}/prices up to 500 rows.
Each counts as one request against your rate limit.
"""
import sys
import uuid
from collections import Counter

from slflo import Slflo, TokenRefused, report

BATCH = 500
LIST = "WHOLESALE-EGP"
RUN = uuid.uuid4().hex[:12]


def chunks(rows, size=BATCH):
    for start in range(0, len(rows), size):
        yield start // size, rows[start:start + size]


# region batches
def load(api, products, prices):
    api.put("/units/PCS", {"name": {"en": "Piece"}}, key=f"{RUN}:unit:PCS")
    api.put("/units/CTN", {"name": {"en": "Carton"}}, key=f"{RUN}:unit:CTN")
    api.put(f"/price-lists/{LIST}", {"name": {"en": "Wholesale"}, "currency": "EGP"}, key=f"{RUN}:list")

    pushed, failed = Counter(), []
    for n, chunk in chunks(products):
        answer = api.post("/batch/products", {"items": chunk}, key=f"{RUN}:products:{n}")
        for item in answer["data"]:
            if item["ok"]:
                pushed[item["result"]["result"]] += 1         # created / updated / unchanged / stale
            else:
                failed.append((item["ref"], item["error"]["code"]))  # this item only; the rest went in

    # merge (the default) adds and updates rows and leaves the list's other prices alone,
    # so a list longer than 500 rows can go in several calls.
    written = unchanged = calls = 0
    for n, chunk in chunks(prices):
        answer = api.put(f"/price-lists/{LIST}/prices", {"prices": chunk},
                         key=f"{RUN}:prices:{n}", query={"mode": "merge"})["data"]
        written, unchanged, calls = written + answer["written"], unchanged + answer["unchanged"], calls + 1
    return {"products": dict(pushed), "failed": failed,
            "prices": {"calls": calls, "written": written, "unchanged": unchanged}}
# endregion


def erp_catalogue():
    """Stands in for your ERP's item and trade-agreement tables."""
    products, prices = [], []
    for i in range(1, 1001):
        ref = f"ITEM-B{i:04d}"
        products.append({"ref": ref, "body": {"name": {"en": f"Item {i}"}, "base_unit_ref": "PCS", "active": True}})
        piece = 5 + (i % 40) * 0.25
        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 * 12, 2), "valid_from": "2026-01-01"})
    return products, prices


def main():
    try:
        summary = load(Slflo(), *erp_catalogue())
    except TokenRefused as stop:
        report({"stopped_by": stop.code})
        return 3
    report(summary)
    return 0


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