#!/usr/bin/env python3
import argparse, hashlib, json, sys

ZERO='0'*64

def canon(x):
    return json.dumps(x, sort_keys=True, separators=(',',':'), ensure_ascii=False).encode()
def digest(x): return hashlib.sha256(canon(x)).hexdigest()

def validate(path):
    errors=[]; rows=[]
    with open(path, encoding='utf-8') as f:
        for n,line in enumerate(f,1):
            if not line.strip(): continue
            try: r=json.loads(line)
            except Exception as e: errors.append(f'{n}: invalid_json:{e}'); continue
            rows.append(r)
            required={'seq','prev_hash','payload','self_hash'}
            missing=required-r.keys()
            if missing: errors.append(f'{n}: missing:{sorted(missing)}'); continue
            expected_self=digest({'seq':r['seq'],'prev_hash':r['prev_hash'],'payload':r['payload']})
            if r['self_hash'] != expected_self: errors.append(f'{n}: HASH_SELF')
            p=r['payload']
            if p.get('kind')=='fact':
                if not p.get('provenance'): errors.append(f'{n}: PROVENANCE_REQUIRED')
            if p.get('kind')=='inherited_fact' or p.get('inherited') is True:
                errors.append(f'{n}: INHERITED_NOT_FACT')
    for i,r in enumerate(rows):
        expected=ZERO if i==0 else rows[i-1].get('self_hash')
        if r.get('seq') != i: errors.append(f'{i+1}: SEQ')
        if r.get('prev_hash') != expected: errors.append(f'{i+1}: HASH_CHAIN')
    return errors

def main():
    ap=argparse.ArgumentParser(); ap.add_argument('file'); args=ap.parse_args()
    e=validate(args.file)
    print(json.dumps({'ok':not e,'errors':e,'records':sum(1 for _ in open(args.file,encoding='utf-8'))}, sort_keys=True))
    return 0 if not e else 1
if __name__=='__main__': sys.exit(main())
