"""Check a ParetoAlpha prudence file offline. Standard library only; needs verify.py beside it.

    python3 verify_prudence.py prudence-file.json

It recomputes, from the file alone:
  1. the file's digest: sha256 of the canonical form of everything but "digest";
  2. the sealed answer's hash, from the body carried inside the file;
  3. whether the answer was sealed before the decision was recorded;
  4. the path from the family's records to that day's root on the public log (paretoalphasystems.com/log).
Then it prints the factors the record addresses in sealed fields. Nothing is fetched; to confirm the root and
the answer are on the public record, open the two links it prints.

The canonical form is verify.py's: keys sorted, no whitespace, numbers at 12 significant digits (15 from 1e10).
"""
import hashlib, json, sys
from verify import _dump


def sha(s: str) -> str:
    return hashlib.sha256(s.encode("utf-8")).hexdigest()


def node(left: str, right: str) -> str:
    return sha(f"node|{left}|{right}")


def check(path: str) -> int:
    f = json.load(open(path, encoding="utf-8"))
    bad = 0

    def line(ok, text):
        nonlocal bad
        bad += 0 if ok else 1
        print(("  ok    " if ok else "  FAIL  ") + text)

    body = {k: v for k, v in f.items() if k != "digest"}
    line(sha(_dump(body)) == f.get("digest"), f"file digest {f.get('digest', '')[:16]}…")

    a = f.get("answer")
    if a:
        line(sha(_dump(a["body"])) == a["proofHash"], f"sealed answer {a['proofHash'][:16]}… recomputes from its body")
        line(a["sealedAt"] <= f["decision"]["decidedAt"], f"sealed {a['sealedAt'][:19]} before the decision {f['decision']['decidedAt'][:19]}")
    else:
        print("  --    no sealed answer in this file")

    log = f.get("log")
    if log:
        h = log["leaf"]
        for step in log["path"]:
            h = node(h, step["hash"]) if step["side"] == "R" else node(step["hash"], h)
        line(h == log["root"], f"the family's record is under the public log root of {log['date']} ({log['root'][:16]}…)")
    else:
        print("  --    no public log path in this file (a sample, or before the first log entry)")

    rows = f["factors"]["upia"] + f["factors"]["duties"]
    structured = [r for r in rows if r["status"] == "structured"]
    print(f"\n  {len(structured)} of {len(rows)} UPIA factors and duties are addressed in sealed fields:")
    for r in rows:
        print(f"    [{r['status']:>10}]  {r['source']}  {r['text'][:70]}")
    print("\n  Confirm online:")
    if a:
        print(f"    https://paretoalphasystems.com/verify?hash={a['proofHash']}")
    if log:
        print(f"    https://paretoalphasystems.com/api/log/{log['date']}")
    print("\n  " + ("VERIFIED" if bad == 0 else f"{bad} CHECK(S) FAILED"))
    return 0 if bad == 0 else 1


if __name__ == "__main__":
    sys.exit(check(sys.argv[1]))
