"""Standalone chain verifier (Python standard library only). Download the chain and this file, then:

  python verify.py chain.jsonl

Each record's hash is sha256 over the record without its "hash" field, serialised with
json.dumps(sort_keys=True, separators=(",", ":")); each record's "prev" must equal the previous record's hash.
A held record carries its original hash but not its text, so its link verifies and its content is reported as withheld.
"""
import hashlib
import json
import sys

GENESIS = "0" * 64


def digest(value) -> str:
    return hashlib.sha256(json.dumps(value, sort_keys=True, separators=(",", ":")).encode()).hexdigest()


def main(path: str, expected_head=None) -> int:
    prev, ok, withheld = GENESIS, 0, 0
    with open(path, encoding="utf-8") as f:
        for i, line in enumerate(l for l in f if l.strip()):
            rec = json.loads(line)
            if rec.get('schema_version') == 1:
                if rec.get('sequence') != i+1 or rec.get('previous_hash') != prev or digest({k:v for k,v in rec.items() if k!='hash'}) != rec.get('hash'):
                    print(f'RESEARCH CHAIN BROKEN at event {i+1}')
                    return 1
                ok += 1; prev=rec['hash']; continue
            if rec.get("n") != i or rec.get("prev") != prev:
                print(f"BROKEN LINK at record {i} (n={rec.get('n')})")
                return 1
            if rec.get("withheld"):
                withheld += 1
            elif digest({k: v for k, v in rec.items() if k != "hash"}) != rec.get("hash"):
                print(f"CONTENT CHANGED at record {i} (n={rec.get('n')})")
                return 1
            else:
                ok += 1
            prev = rec["hash"]
    if expected_head and prev != expected_head:
        print('HEAD MISMATCH: missing tail or wrong checkpoint'); return 1
    print(f"chain ok: {ok} records verified, {withheld} withheld (link only), head {prev}")
    return 0


if __name__ == "__main__":
    import argparse
    ap=argparse.ArgumentParser();ap.add_argument('path');ap.add_argument('--head');args=ap.parse_args()
    sys.exit(main(args.path,args.head))
