#!/usr/bin/env python3
"""External-auditor verifier for the BO proof run — KEY-FREE, no trust in BlindOracle.

Confirms, independently, that every agent activity in manifest.json is backed by a
verifiable proof:

  CHECK 1  Delegation integrity   — each 30014 record's event_id == sha256(canonical(rec-event_id))
  CHECK 2  Delegation chain        — each record's prev_hash links the previous event_id
  CHECK 3  Delegation completeness — every delegation_event_id cited in the manifest exists in the log
  CHECK 4  On-chain settlement     — each settled tx_hash is confirmed on Base (public RPC),
                                      status success, to the USDC contract. No API key, no node of ours.

Usage:  python3 auditor_verify.py [manifest.json] [delegation_proofs.jsonl]
Exit 0 = all checks pass; 1 = a failure (printed).
"""
import hashlib, json, sys, urllib.request
from pathlib import Path

HERE = Path(__file__).resolve().parent
DELEGATION_KIND = 30014
USDC_BASE = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
BASE_RPCS = ["https://base-rpc.publicnode.com", "https://mainnet.base.org", "https://base.llamarpc.com"]


def _event_id(rec):
    payload = {k: v for k, v in rec.items() if k != "event_id"}
    return hashlib.sha256(json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()).hexdigest()


def load_jsonl(p):
    return [json.loads(l) for l in Path(p).read_text().splitlines() if l.strip()]


def rpc(method, params):
    body = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params}).encode()
    last = None
    for url in BASE_RPCS:
        try:
            req = urllib.request.Request(url, data=body, headers={"Content-Type": "application/json", "User-Agent": "bo-auditor/1.0"})
            with urllib.request.urlopen(req, timeout=20) as r:
                return json.loads(r.read().decode()).get("result")
        except Exception as e:  # noqa: BLE001
            last = e
    raise RuntimeError(f"all Base RPCs failed: {last}")


def main():
    manifest_p = sys.argv[1] if len(sys.argv) > 1 else HERE / "manifest.json"
    log_p = sys.argv[2] if len(sys.argv) > 2 else HERE / "delegation_proofs.jsonl"
    m = json.loads(Path(manifest_p).read_text())
    recs = [r for r in load_jsonl(log_p) if r.get("kind") == DELEGATION_KIND]
    fails = []

    # CHECK 1 + 2 — delegation integrity + chain
    last_eid = None
    for i, r in enumerate(recs):
        if _event_id(r) != r.get("event_id"):
            fails.append(f"CHECK1 integrity: record {i} event_id mismatch")
        if i > 0 and r.get("prev_hash") != last_eid:
            fails.append(f"CHECK2 chain: record {i} prev_hash != previous event_id")
        last_eid = r.get("event_id")
    print(f"CHECK 1 integrity  : {len(recs)} delegation records hashed — {'OK' if not any('CHECK1' in f for f in fails) else 'FAIL'}")
    print(f"CHECK 2 chain      : prev_hash links — {'OK (unbroken)' if not any('CHECK2' in f for f in fails) else 'FAIL'}")

    # CHECK 3 — completeness vs manifest
    have = {r.get("event_id") for r in recs}
    cited = [eid for it in m["interactions"] for eid in (it.get("delegation_event_ids") or [])]
    missing = [e for e in cited if e not in have]
    print(f"CHECK 3 completeness: {len(cited)} cited delegation ids, {len(missing)} missing — {'OK' if not missing else 'FAIL'}")
    if missing:
        fails.append(f"CHECK3 completeness: {len(missing)} cited delegation ids absent from log")

    # CHECK 4 — on-chain settlement (independent Base RPC)
    settled = [it for it in m["interactions"] if it.get("ok") and it.get("tx_hash")]
    ok_chain = 0
    for it in settled:
        try:
            rcpt = rpc("eth_getTransactionReceipt", [it["tx_hash"]])
            status_ok = rcpt and rcpt.get("status") == "0x1"
            to_usdc = rcpt and (rcpt.get("to", "").lower() == USDC_BASE)
            if status_ok and to_usdc:
                ok_chain += 1
            else:
                fails.append(f"CHECK4 tx {it['tx_hash'][:12]}: status_ok={status_ok} to_usdc={to_usdc}")
        except Exception as e:  # noqa: BLE001
            fails.append(f"CHECK4 tx {it['tx_hash'][:12]}: RPC error {str(e)[:80]}")
    print(f"CHECK 4 on-chain   : {ok_chain}/{len(settled)} settled txs confirmed on Base (status=1, to=USDC) — {'OK' if ok_chain == len(settled) and settled else 'FAIL'}")

    print("-" * 60)
    print(f"interactions: {m['n_requested']}  settled_ok: {m['settled_ok']}  "
          f"total_usd: {m['total_usd_settled']}  distinct agents: {m['distinct_consumer_agents']}")
    if fails:
        print("RESULT: FAIL")
        for f in fails[:20]:
            print("  -", f)
        return 1
    print("RESULT: PASS — every agent activity independently verified (delegation chain + on-chain settlement), no trust in BlindOracle required.")
    return 0


if __name__ == "__main__":
    sys.exit(main())
