#!/usr/bin/env python3
import argparse, hashlib, json, sys
REQUIRED={"id","contract","state","head_hash","provenance","inherited"}
def refuse(code,detail):
 print(json.dumps({"ok":False,"code":code,"detail":detail},sort_keys=True)); return 1
def consume(path, expected_contract, expected_head=None):
 rows=[]
 try:
  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 json.JSONDecodeError as e:return refuse("REFUSE_JSON",f"line {n}: {e.msg}")
    missing=REQUIRED-set(r)
    if missing:return refuse("REFUSE_SCHEMA",f"line {n}: missing {sorted(missing)}")
    rows.append(r)
 except OSError as e:return refuse("REFUSE_IO",str(e))
 if not rows:return refuse("REFUSE_EMPTY","no resume records")
 for i,r in enumerate(rows):
  if not isinstance(r["id"],int) or r["id"]<=0:return refuse("REFUSE_ID",f"record {i}: id")
  if r["contract"]!=expected_contract:return refuse("REFUSE_CONTRACT",f"record {r['id']}: {r['contract']}")
  if r["inherited"] is True:return refuse("REFUSE_INHERITED",f"record {r['id']} marked inherited")
  if not r["provenance"]:return refuse("REFUSE_PROVENANCE",f"record {r['id']}")
  if not isinstance(r["head_hash"],str) or len(r["head_hash"])<8:return refuse("REFUSE_HEAD",f"record {r['id']}")
  if i and r["id"]!=rows[i-1]["id"]+1:return refuse("REFUSE_SEQUENCE",f"expected {rows[i-1]['id']+1}, got {r['id']}")
 head=rows[-1]["head_hash"]
 if expected_head is not None and head!=expected_head:return refuse("REFUSE_HEAD_MISMATCH",f"expected {expected_head}, got {head}")
 raw="".join(json.dumps(r,sort_keys=True,separators=(",",":"))+"\n" for r in rows).encode()
 print(json.dumps({"ok":True,"code":"RESUME_CONSUMED","contract":expected_contract,"first_id":rows[0]["id"],"last_id":rows[-1]["id"],"records":len(rows),"validated_head_hash":head,"ledger_sha256":hashlib.sha256(raw).hexdigest(),"state":rows[-1]["state"]},sort_keys=True)); return 0
if __name__=="__main__":
 p=argparse.ArgumentParser();p.add_argument("ledger");p.add_argument("--contract",required=True);p.add_argument("--expected-head");a=p.parse_args();sys.exit(consume(a.ledger,a.contract,a.expected_head))
