#!/usr/bin/env python3
"""Two marketplaces, one rail — offline verification of a buyer kit and a seller kit.

Per kit (each side, independently): every sampled deal is recomputed from its record → record
hash → Merkle path → snapshot root → 32-byte commitment == door payload → ledger leaf
(recomputed) → beat root → NEOva2 bundle (pinned witnesses) → public unit. Across the kits:
the same deal (contract number) names the SAME relation in both books, and both sides reach a
witnessed position. Nothing asserted, everything rederived. Prints PASS/FAIL with counts.
"""
from __future__ import annotations

import argparse
import hashlib
import json
import sys
from pathlib import Path


def verify_kit(kit: Path, member: str, reg, P, S, record_hash, InclusionProof, _leaf_hash, DEFAULT_PROFILE, content_hash, with_profile):
    e = json.loads((kit / "edge.json").read_text())
    rc = json.loads((kit / "neocl.json").read_text())
    bs = json.loads((kit / "neova2.json").read_text())
    hs = json.loads((kit / "hour.json").read_text())
    ed, ep = e["edge"]["edge_id"], e["edge"]["epoch"]
    pid = DEFAULT_PROFILE.id() if callable(DEFAULT_PROFILE.id) else DEFAULT_PROFILE.id
    bundle_ok = {root: bool(P.verify_bundle(b, trusted_registry=reg).get("valid")) for root, b in bs.items()}
    hour_ok = {k: bool(P.verify_hour_view(h).get("valid")) for k, h in hs.items()}
    fails, deals = [], {}
    for s in e["seconds"]:
        body = {k: v for k, v in s["snapshot"].items() if k != "snapshot_schema"}
        snap = S.Snapshot(**body)
        fs = str(s["frame_seq"]); r = rc.get(fs); rcp = e["receipts"].get(fs)
        def bad(why): fails.append({"sec": s["sec"], "why": why})
        if snap.snapshot_hash() != s["commitment"]: bad("commitment != snapshot hash"); continue
        if r is None: bad("no ledger receipt"); continue
        if rcp is None or hashlib.sha256(bytes.fromhex(s["commitment"])).hexdigest() != rcp["payload_sha256"]:
            bad("commitment != door payload"); continue
        lineage = f"fx.{ed}.{ep}.{s['frame_seq']}"
        rid, rel = f"{lineage}.0", f"{lineage}.{rcp['payload_sha256'][:16]}"
        stamp = content_hash(pid, "NEOCL:THIN_STAMP:V1", with_profile(
            {"member": member, "edge_seal": s["commitment"], "relation_ref": rel, "request_id": rid}, pid))
        if r["request_id"] != rid or _leaf_hash(stamp, DEFAULT_PROFILE).hex() != r["leaf"]:
            bad("ledger leaf does not recompute"); continue
        pr = r["proof"]
        if not InclusionProof(pr["leaf_index"], pr["leaf_count"], bytes.fromhex(r["leaf"]),
                              tuple((bytes.fromhex(x), bool(y)) for x, y in pr["audit_path"])).verifies_to(bytes.fromhex(r["root"])):
            bad("leaf not in beat root"); continue
        b = bs.get(r["root"])
        if b is None or not bundle_ok.get(r["root"]): bad("no valid NEOva2 bundle"); continue
        hp = str(b["ladder"][0]["record"]["period_id"]); h = hs.get(hp)
        if h is None or not hour_ok.get(hp): bad("public unit invalid"); continue
        if not any(p["range_start"] <= b["position"] < p["range_start"] + p["count"] for p in h["positions"]):
            bad("position not in public unit"); continue
        for smp in s["sample"]:
            ok = record_hash(smp["record"]) == smp["record_hash"] and S.verify_path(smp["record_hash"], smp["path"], body["root"])
            if not ok: bad(f"deal {smp['contract']} does not reach the snapshot root"); continue
            deals[smp["contract"]] = {"relation_ref": smp["relation_ref"], "position": b["position"], "hour": int(hp),
                                      "doc_kind": smp["record"].get("doc_kind"), "commitment": s["commitment"]}
    return {"edge_id": ed, "side": e["edge"]["side"], "system_id": e["edge"]["system_id"],
            "deals_total": e["totals"]["deals"], "rate_per_s": e["totals"]["rate_per_s"], "seconds": len(e["seconds"]),
            "deals_proven": len(deals), "fails": fails, "deals": deals}


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--buyer", required=True); ap.add_argument("--seller", required=True)
    ap.add_argument("--pinned", required=True); ap.add_argument("--member", default="neofx-internal-e2e")
    ap.add_argument("--neova-path", default="/root/scan-lab/neova2-src/neova")
    ap.add_argument("--neoedge-path", default="")
    ap.add_argument("--out", default="")
    a = ap.parse_args()
    if a.neoedge_path: sys.path.insert(0, a.neoedge_path)
    sys.path.insert(0, a.neova_path)
    from neova import proofs as P, witness_keys as WK
    from neoedge import snapshot as S
    from neoedge.grammar import record_hash
    from cl.anchor.merkle import InclusionProof, _leaf_hash
    from cl.canonical.hash_profile import DEFAULT_PROFILE, content_hash, with_profile
    reg = WK.load_qualified(a.pinned)
    args = (a.member, reg, P, S, record_hash, InclusionProof, _leaf_hash, DEFAULT_PROFILE, content_hash, with_profile)
    B = verify_kit(Path(a.buyer), *args); Sx = verify_kit(Path(a.seller), *args)
    common = sorted(set(B["deals"]) & set(Sx["deals"]))
    same_relation = [c for c in common if B["deals"][c]["relation_ref"] == Sx["deals"][c]["relation_ref"]]
    cross = {"deals_in_both_kits": len(common), "same_relation_both_sides": len(same_relation),
             "buyer_only": len(set(B["deals"]) - set(Sx["deals"])), "seller_only": len(set(Sx["deals"]) - set(B["deals"])),
             "example": ({"contract": same_relation[0], "relation_ref": B["deals"][same_relation[0]]["relation_ref"],
                          "buyer": B["deals"][same_relation[0]], "seller": Sx["deals"][same_relation[0]]} if same_relation else None)}
    verdict = "PASS" if not B["fails"] and not Sx["fails"] and common and len(same_relation) == len(common) else "FAIL"
    out = {"verdict": verdict, "buyer": {k: v for k, v in B.items() if k != "deals"},
           "seller": {k: v for k, v in Sx.items() if k != "deals"}, "cross": cross,
           "not_proven": ["era seal (witnessed != sealed)", "business truth of the documents"]}
    if a.out: Path(a.out).write_text(json.dumps(out, sort_keys=True, indent=1))
    print(json.dumps({"verdict": verdict, "buyer_deals": B["deals_total"], "seller_deals": Sx["deals_total"],
                      "proven_buyer": B["deals_proven"], "proven_seller": Sx["deals_proven"], **{k: v for k, v in cross.items() if k != "example"},
                      "fails": len(B["fails"]) + len(Sx["fails"])}))
    return 0 if verdict == "PASS" else 1


if __name__ == "__main__":
    raise SystemExit(main())
