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

REQUIRED = ('agent_id','continuity_contract','caller_mode','referent','records')

def sha(obj):
    return hashlib.sha256(json.dumps(obj, sort_keys=True, separators=(',',':')).encode()).hexdigest()

def verify(packet):
    missing=[k for k in REQUIRED if k not in packet]
    if missing: return False, 'REFUSE_MISSING:' + ','.join(missing)
    if packet.get('caller_mode') not in ('owner-issued','replay'):
        return False, 'REFUSE_CALLER_MODE'
    ref=packet['referent']
    if not isinstance(ref,dict) or not ref.get('id') or not ref.get('version'):
        return False, 'REFUSE_REFERENT'
    records=packet['records']
    if not isinstance(records,list) or not records: return False, 'REFUSE_RECORDS'
    prev='0'*64
    for i,r in enumerate(records):
        if r.get('seq') != i: return False, 'REFUSE_SEQUENCE'
        if r.get('prev_hash') != prev: return False, 'REFUSE_CHAIN'
        if r.get('status') == 'INHERITED': return False, 'REFUSE_INHERITED_NOT_FACT'
        body={k:v for k,v in r.items() if k not in ('self_hash',)}
        if r.get('self_hash') != sha(body): return False, 'REFUSE_SELF_HASH'
        prev=r['self_hash']
    return True, 'PASS'

def main():
    ap=argparse.ArgumentParser(); ap.add_argument('packet'); ap.add_argument('--state',required=True); ap.add_argument('--receipt',required=True)
    a=ap.parse_args(); p=json.loads(pathlib.Path(a.packet).read_text()); ok,reason=verify(p)
    receipt={'agent_id':p.get('agent_id'),'referent':p.get('referent'),'result':reason,'packet_hash':sha(p)}
    pathlib.Path(a.receipt).write_text(json.dumps(receipt,sort_keys=True)+'\n')
    if ok:
        pathlib.Path(a.state).write_text(json.dumps({'resumed_from':p['referent'],'packet_hash':receipt['packet_hash']})+'\n')
        print('PASS')
        return 0
    print(reason, file=sys.stderr); return 1
if __name__=='__main__': sys.exit(main())
