#!/usr/bin/env python3
"""Verify a VidMee signed evidence pack — offline, without trusting VidMee.

Usage:
  python3 verify-evidence.py pack.json [asset_file ...] [--key <public_key_b64>]

  pack.json     the response of POST https://api.vidmee.ai/v1/evidence/{job_id}
  asset_file    optional: downloaded artifact(s) to check against the manifest's SHA-256
                (screenshots download via the signed URL in the job result)
  --key         optional: pinned public key; otherwise fetched from
                https://api.vidmee.ai/v1/evidence/key

Requires: pip install cryptography

Checks, in order:
  1. Ed25519 signature over the canonical manifest bytes
  2. `manifest` re-serialization (sorted keys, compact separators) equals the signed bytes
  3. each provided asset file's SHA-256 appears in the manifest
Exit code 0 = verified; 1 = FAILED.
"""

import base64
import hashlib
import json
import sys
import urllib.request

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

KEY_URL = "https://api.vidmee.ai/v1/evidence/key"


def fetch_key() -> str:
    req = urllib.request.Request(KEY_URL, headers={"User-Agent": "vidmee-verify/1.0"})
    with urllib.request.urlopen(req) as r:
        return json.load(r)["public_key_b64"]


def main() -> int:
    args = [a for a in sys.argv[1:]]
    key_b64 = None
    if "--key" in args:
        i = args.index("--key")
        key_b64 = args[i + 1]
        del args[i:i + 2]
    if not args:
        print(__doc__)
        return 1
    pack = json.load(open(args[0]))
    asset_files = args[1:]

    pub = Ed25519PublicKey.from_public_bytes(base64.b64decode(key_b64 or fetch_key()))
    body = base64.b64decode(pack["canonical_manifest_b64"])
    try:
        pub.verify(base64.b64decode(pack["signature_b64"]), body)
        print("[1/3] signature: VALID")
    except Exception:
        print("[1/3] signature: FAILED — pack is not authentic")
        return 1

    manifest = pack["manifest"]
    if json.dumps(manifest, sort_keys=True, separators=(",", ":")).encode() != body:
        print("[2/3] canonical bytes: MISMATCH — manifest was altered after signing")
        return 1
    print("[2/3] canonical bytes: MATCH")

    manifest_hashes = {a["sha256"] for a in manifest.get("assets", []) if a.get("sha256")}
    ok = True
    for f in asset_files:
        h = hashlib.sha256(open(f, "rb").read()).hexdigest()
        hit = h in manifest_hashes
        ok = ok and hit
        print(f"[3/3] {f}: sha256 {'MATCHES manifest' if hit else 'NOT IN MANIFEST — FAILED'}")
    if not asset_files:
        print("[3/3] no asset files provided — signature and manifest verified only")

    print("\nVERIFIED" if ok else "\nFAILED")
    print(f"job={manifest['job_id']} op={manifest['operation']} signed_at={manifest['signed_at']}")
    return 0 if ok else 1


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