#!/usr/bin/env python3
"""Rebuild the bundled synthetic CSV from the bundled source-shaped JSON.

Run this file with Python 3, or add --check to verify the existing CSV.
Uses the standard library and local files only. This is a teaching normaliser,
with invented account/report/status metadata, not a live Amazon extraction.
"""

import argparse
import csv
import io
import json
from decimal import Decimal
from pathlib import Path

HERE = Path(__file__).resolve().parent
SOURCE = HERE / "vendor-sales-source.json"
OUTPUT = HERE / "vendor-sales.csv"
COLUMNS = (
    "vendor_account_id", "marketplace_id", "report_type", "report_period",
    "distributor_view", "selling_program", "report_timezone", "source_report_id",
    "processing_status", "source_last_updated_date", "extracted_at", "start_date",
    "end_date", "asin", "currency", "ordered_units", "ordered_revenue",
    "shipped_units", "shipped_revenue", "customer_returns", "reported_shipped_cogs",
)


def require(condition, message):
    if not condition:
        raise ValueError(message)


def amount(value):
    parsed = Decimal(str(value))
    require(parsed.is_finite() and parsed == parsed.quantize(Decimal("0.01")),
            "Teaching monetary values must be finite and exact to cents")
    return format(parsed, ".2f")


def count(value):
    parsed = Decimal(str(value))
    require(parsed.is_finite() and parsed >= 0 and parsed == parsed.to_integral_value(),
            "Teaching counts must be non-negative integers")
    return str(int(parsed))


def normalise(source):
    spec = source["reportSpecification"]
    options = spec["reportOptions"]
    require(spec["reportType"] == "GET_VENDOR_SALES_REPORT", "Expected Vendor Sales report")
    require(options == {"distributorView": "MANUFACTURING", "reportPeriod": "DAY", "sellingProgram": "RETAIL"},
            "Teaching model requires MANUFACTURING / RETAIL / DAY")
    require(len(spec["marketplaceIds"]) == 1, "Teaching model requires one marketplace")
    rows = []
    for item in source["salesByAsin"]:
        currencies = {item[field]["currencyCode"] for field in ("orderedRevenue", "shippedRevenue", "shippedCogs")}
        require(len(currencies) == 1, "Mixed monetary currencies within a source row")
        row = {
            "vendor_account_id": "SYN-VENDOR", "marketplace_id": spec["marketplaceIds"][0],
            "report_type": spec["reportType"], "report_period": options["reportPeriod"],
            "distributor_view": options["distributorView"], "selling_program": options["sellingProgram"],
            "report_timezone": "PST", "source_report_id": "SYN-REPORT", "processing_status": "DONE",
            "source_last_updated_date": spec["lastUpdatedDate"], "extracted_at": "2026-09-18T12:00:00Z",
            "start_date": item["startDate"], "end_date": item["endDate"], "asin": item["asin"],
            "currency": next(iter(currencies)), "ordered_units": count(item["orderedUnits"]),
            "ordered_revenue": amount(item["orderedRevenue"]["amount"]),
            "shipped_units": count(item["shippedUnits"]),
            "shipped_revenue": amount(item["shippedRevenue"]["amount"]),
            "customer_returns": count(item["customerReturns"]),
            "reported_shipped_cogs": amount(item["shippedCogs"]["amount"]),
        }
        rows.append(row)
    require(len({row["currency"] for row in rows}) == 1, "Teaching model requires one currency")
    keys = [(row["start_date"], row["end_date"], row["asin"]) for row in rows]
    require(len(keys) == len(set(keys)), "Duplicate ASIN/reporting-period source rows")
    # salesAggregate is retained in the JSON as a control, never appended to the fact.
    return sorted(rows, key=lambda row: (row["start_date"], row["end_date"], row["asin"]))


def csv_text(rows):
    output = io.StringIO(newline="")
    writer = csv.DictWriter(output, fieldnames=COLUMNS, lineterminator="\n")
    writer.writeheader()
    writer.writerows(rows)
    return output.getvalue()


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--check", action="store_true")
    args = parser.parse_args()
    rows = normalise(json.loads(SOURCE.read_text(encoding="utf-8"), parse_float=Decimal))
    generated = csv_text(rows)
    if args.check:
        require(OUTPUT.read_bytes() == generated.encode("utf-8"), "CSV differs from normalised teaching source")
    else:
        OUTPUT.write_bytes(generated.encode("utf-8"))
    print(f"PASS: {len(rows)} synthetic ASIN rows; local CSV {'checked' if args.check else 'written'}.")


if __name__ == "__main__":
    main()
