"""PMC synthetic demonstration v1. Python 3.10+, standard library, offline.
Default: recompute and compare to reference files without writing anything.
--output DIRECTORY: generate results in a separate directory.
This is a fixed teaching fixture, not a general client data importer.
"""
import argparse
import csv
import hashlib
import io
import json
from decimal import Decimal, ROUND_HALF_UP
from pathlib import Path

BASE = Path(__file__).resolve().parent
FIELDS = ["record_id", "month", "revenue_kpln", "cost_kpln"]


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


def calculate(raw):
    reader = csv.DictReader(io.StringIO(raw.decode("utf-8")))
    if reader.fieldnames != FIELDS:
        raise ValueError("Unexpected CSV structure")
    clean, exceptions, seen = [], [], set()
    for line, row in enumerate(reader, 2):
        if None in row or any(row[k] is None or row[k] == "" for k in FIELDS):
            reason = "missing_field"
        elif row["record_id"] in seen:
            # This fixture contains an exact duplicate; conflicts stop the run.
            previous = next(r for r in clean if r["record_id"] == row["record_id"])
            if previous != row:
                raise ValueError("Conflicting ID: agree a rule before proceeding")
            reason = "exact_duplicate"
        else:
            if row["month"] not in [f"{m:02}" for m in range(1, 13)]:
                raise ValueError("Invalid month")
            values = [Decimal(row[k]) for k in FIELDS[2:]]
            if any(not v.is_finite() or v < 0 for v in values):
                raise ValueError("Invalid amount")
            seen.add(row["record_id"])
            clean.append(row)
            continue
        exceptions.append({"source_line": str(line), "record_id": row["record_id"], "reason": reason})
    revenue = sum((Decimal(r["revenue_kpln"]) for r in clean), Decimal(0))
    cost = sum((Decimal(r["cost_kpln"]) for r in clean), Decimal(0))
    if revenue == 0:
        raise ValueError("Margin undefined for zero revenue")
    margin = ((revenue-cost)/revenue*100).quantize(Decimal("0.1"), rounding=ROUND_HALF_UP)
    summary = {"scope": "synthetic_demo_v1", "input_sha256": hashlib.sha256(raw).hexdigest(),
               "input_rows": len(clean)+len(exceptions), "accepted_rows": len(clean),
               "exception_rows": len(exceptions), "revenue_kpln": str(revenue),
               "cost_kpln": str(cost), "difference_kpln": str(revenue-cost),
               "margin_percent": str(margin), "accepted_records": clean}
    return {"clean.csv": csv_text(FIELDS, clean),
            "exceptions.csv": csv_text(["source_line", "record_id", "reason"], exceptions),
            "result.json": json.dumps(summary, ensure_ascii=False, indent=2)+"\n"}


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--output", type=Path)
    args = parser.parse_args()
    outputs = calculate((BASE/"input.csv").read_bytes())
    if args.output:
        if args.output.resolve() == BASE:
            parser.error("Use a separate output directory to protect the references")
        args.output.mkdir(parents=True, exist_ok=True)
        for name, content in outputs.items():
            (args.output/name).write_text(content, encoding="utf-8", newline="\n")
        print("Generated synthetic results; compare with the published reference files.")
    else:
        for name, expected in outputs.items():
            if (BASE/name).read_bytes() != expected.encode("utf-8"):
                raise SystemExit(f"FAIL: reference mismatch: {name}")
        # Independent, fixed expectations for this public fixture.
        result = json.loads(outputs["result.json"])
        expected = {"input_rows": 8, "accepted_rows": 6, "exception_rows": 2,
                    "revenue_kpln": "480", "cost_kpln": "365",
                    "difference_kpln": "115", "margin_percent": "24.0"}
        if any(result[k] != v for k, v in expected.items()):
            raise SystemExit("FAIL: fixed fixture expectations")
        print("PASS: 8 = 6 + 2 rows; revenue 480; costs 365; difference 115; margin 24.0%. Synthetic only.")


if __name__ == "__main__":
    main()
