#!/usr/bin/env python3
"""Offline verifier for Fifty50 contribution event audit chains.

Usage:
    python verify_audit_chain.py path/to/events.json

Input JSON shape (from Fifty50's exported trail):
    {"events": [{"event_type", "actor_id", "occurred_at", "details", "entry_hash"}, ...]}

Prints PASS or "TAMPERED <index>" and exits 0 / 1.

This file intentionally DUPLICATES the canonical hash logic (it imports nothing from Fifty50) so a
customer can read this one file and trust the math without installing Fifty50 or trusting our
database. It must stay byte-for-byte identical to fifty50/core/audit_chain.py's canonical form.
"""
from __future__ import annotations

import hashlib
import json
import sys
from datetime import datetime, timezone
from typing import Any

GENESIS_PREV = ""


def _as_utc(dt: datetime) -> datetime:
    return dt.replace(tzinfo=timezone.utc) if dt.tzinfo is None else dt.astimezone(timezone.utc)


def canonical_occurred_at(value: Any) -> str:
    if isinstance(value, datetime):
        dt = value
    elif isinstance(value, str):
        s = value.strip()
        if s.endswith("Z"):
            s = s[:-1] + "+00:00"
        dt = datetime.fromisoformat(s)
    else:
        raise TypeError(f"occurred_at must be datetime or str, got {type(value)!r}")
    dt = _as_utc(dt)
    return dt.strftime("%Y-%m-%dT%H:%M:%S.") + f"{dt.microsecond:06d}Z"


def canonical_event_bytes(event: dict) -> bytes:
    payload = {
        "actor_id": event.get("actor_id", "") or "",
        "details": event.get("details", None) or {},
        "event_type": event.get("event_type", ""),
        "occurred_at": canonical_occurred_at(event.get("occurred_at")),
    }
    return json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")


def chain_hash(prev_hex: str, event_content_bytes: bytes) -> str:
    h = hashlib.sha256()
    h.update((prev_hex or "").encode("utf-8"))
    h.update(event_content_bytes)
    return h.hexdigest()


def compute_entry_hash(prev_hex: str, event: dict) -> str:
    return chain_hash(prev_hex or GENESIS_PREV, canonical_event_bytes(event))


def verify_chain(events: list) -> tuple[bool, int]:
    if not events:
        return (True, -1)
    prev = GENESIS_PREV
    for i, event in enumerate(events):
        expected = compute_entry_hash(prev, event)
        if (event.get("entry_hash", "") or "") != expected:
            return (False, i)
        prev = expected
    return (True, -1)


def main(argv: list) -> int:
    if len(argv) != 2:
        print("Usage: verify_audit_chain.py <events.json>", file=sys.stderr)
        return 2
    with open(argv[1], "r", encoding="utf-8") as f:
        data = json.load(f)
    events = data["events"] if isinstance(data, dict) else data
    ok, idx = verify_chain(events)
    if ok:
        print("PASS")
        return 0
    print(f"TAMPERED {idx}")
    return 1


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