#!/usr/bin/env python3
"""Independent verifier for a Magellan evidence pack.

Re-derives every hash from the payloads shown. Requires nothing from Magellan
at runtime: no API keys, no network, no database. Only the Python standard
library.

    python3 verify_chain.py magellan_sample_evidence_pack.json
    python3 verify_chain.py magellan_sample_evidence_pack.json --tamper

Exit code is 0 when the chain verifies and 1 when it does not, so this script
can be dropped into a CI job or an audit workpaper.
"""
import hashlib
import json
import sys

GENESIS = "00" * 32


def canonical(obj) -> bytes:
    """Must match the pack's declared canonicalization exactly."""
    return json.dumps(
        obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False
    ).encode("utf-8")


def verify(pack_path: str, tamper: bool = False) -> int:
    with open(pack_path) as f:
        pack = json.load(f)["evidence_pack"]

    entries = pack["entries"]
    head = pack["chain_head"]

    print("Magellan evidence pack verification")
    print("=" * 62)
    print(f"pack id      : {pack['pack_id']}")
    print(f"product      : {pack['product']} {pack['product_version']}")
    print(f"ledger schema: {pack['ledger_schema']}")
    print(f"sample data  : {pack['sample']}")
    print(f"entries      : {len(entries)}")
    print(f"chain head   : {head['head_hash']}")
    print()
    print("chain parameters")
    print("-" * 62)
    cp = pack["chain_params"]
    print(f"  {cp['entry_hash_formula']}")
    print(f"  {cp['payload_sha256_formula']}")
    print(f"  genesis prev_hash = {cp['genesis_prev_hash'][:16]}... (32 zero bytes)")
    print()

    if tamper:
        # Change one character of one rationale. The payload is re-hashed,
        # so its payload_sha256 moves and every downstream entry_hash breaks.
        target = entries[6]
        print(f"!! demo: altering the rationale of {target['entry_ulid']}")
        target["payload"]["links_reviewed"] = target["payload"]["links_reviewed"] + 1
        print()

    print("walking the chain")
    print("-" * 62)
    prev = bytes.fromhex(GENESIS)
    failures = 0

    for i, e in enumerate(entries, 1):
        recomputed_payload = hashlib.sha256(canonical(e["payload"])).hexdigest()
        payload_ok = recomputed_payload == e["payload_sha256"]

        recomputed_entry = hashlib.sha256(
            prev + bytes.fromhex(e["payload_sha256"])
        ).hexdigest()
        entry_ok = recomputed_entry == e["entry_hash"]

        link_ok = e["prev_hash"] == prev.hex()
        ulid_ok = len(e["entry_ulid"]) == 26

        ok = payload_ok and entry_ok and link_ok and ulid_ok
        if not ok:
            failures += 1

        flag = "PASS" if ok else "FAIL"
        print(
            f"  [{flag}] #{i:02d} {e['entry_type']:<22} "
            f"{e['entry_ulid']}  {e['magellan_role']}"
        )
        if not payload_ok:
            print(f"         payload_sha256 does not match the payload shown")
            print(f"           expected {e['payload_sha256']}")
            print(f"           computed {recomputed_payload}")
        if not entry_ok:
            print(f"         entry_hash does not match prev_hash || payload_sha256")
            print(f"           expected {e['entry_hash']}")
            print(f"           computed {recomputed_entry}")
        if not link_ok:
            print(f"         prev_hash does not point at the preceding entry")
        prev = bytes.fromhex(e["entry_hash"])

    print()
    print("seal checks")
    print("-" * 62)
    ph = pack["partition_head"]
    checks = [
        ("partition first_hash == entry 1", ph["first_hash"] == entries[0]["entry_hash"]),
        ("partition last_hash == final entry", ph["last_hash"] == entries[-1]["entry_hash"]),
        ("partition first_ulid == entry 1", ph["first_ulid"] == entries[0]["entry_ulid"]),
        ("partition last_ulid == final entry", ph["last_ulid"] == entries[-1]["entry_ulid"]),
        ("partition entry_count", ph["entry_count"] == len(entries)),
        ("WORM head == recomputed chain head",
         pack["worm_chain_head"]["head_hash"] == prev.hex()),
        ("chain head matches final entry", head["head_hash"] == entries[-1]["entry_hash"]),
        ("ULIDs strictly increasing",
         all(entries[i]["entry_ulid"] < entries[i + 1]["entry_ulid"]
             for i in range(len(entries) - 1))),
    ]
    for label, ok in checks:
        if not ok:
            failures += 1
        print(f"  [{'PASS' if ok else 'FAIL'}] {label}")

    print()
    if failures:
        print(f"RESULT: CHAIN BROKEN - {failures} check(s) failed.")
        print("        The record was altered after it was written.")
        return 1
    print("RESULT: CHAIN INTACT - every hash re-derived from the payloads shown.")
    print("        No entry can be changed, inserted, removed, or reordered")
    print("        without breaking this result.")
    return 0


if __name__ == "__main__":
    args = [a for a in sys.argv[1:] if a != "--tamper"]
    if not args:
        print("usage: verify_chain.py <pack.json> [--tamper]")
        sys.exit(2)
    sys.exit(verify(args[0], tamper="--tamper" in sys.argv))
