#!/usr/bin/env python3
"""Independent verifier for the sealed cleanup-v5 evidence package."""

from __future__ import annotations

import hashlib
import json
import os
import stat
from pathlib import Path
from typing import Any

ROOT = Path(__file__).parent
V4 = ROOT.parent / "task26-post-lifecycle-cleanup-v4-4a6c7ee5-st_01a00e68"
ARCHIVE = Path("/home/cube/.hermes/profiles/dualcoachtest/data/post-lifecycle-cleanup-archives/task26-current-4a6c7ee5-20260817")
EXCLUDED = {"inventory.json", "SEAL.json"}


def canon(value: Any) -> bytes:
    return (json.dumps(value, sort_keys=True, separators=(",", ":")) + "\n").encode()


def sha(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


def tree_digest(root: Path) -> tuple[str, int]:
    rows: list[dict[str, str]] = []
    for base, dirs, files in os.walk(root, followlinks=False):
        dirs.sort()
        files.sort()
        for name in dirs:
            path = Path(base) / name
            st = path.lstat()
            assert stat.S_ISDIR(st.st_mode), path
            rows.append({"path": path.relative_to(root).as_posix(), "type": "D", "mode": f"{stat.S_IMODE(st.st_mode):04o}"})
        for name in files:
            path = Path(base) / name
            st = path.lstat()
            assert stat.S_ISREG(st.st_mode), path
            rows.append({"path": path.relative_to(root).as_posix(), "type": "F", "mode": f"{stat.S_IMODE(st.st_mode):04o}", "sha256": sha(path)})
    return hashlib.sha256(canon(rows)).hexdigest(), len(rows)


def main() -> int:
    inventory_raw = (ROOT / "inventory.json").read_bytes()
    inventory = json.loads(inventory_raw)
    seal = json.loads((ROOT / "SEAL.json").read_text())
    actual = {path.name for path in ROOT.iterdir() if path.is_file()} - EXCLUDED
    claimed = {row["path"] for row in inventory["entries"]}
    assert actual == claimed, (actual - claimed, claimed - actual)
    for row in inventory["entries"]:
        path = ROOT / row["path"]
        assert path.stat().st_size == row["size"]
        assert f"{stat.S_IMODE(path.stat().st_mode):04o}" == row["mode"]
        assert sha(path) == row["sha256"]
    assert inventory["root_sha256"] == hashlib.sha256(canon(inventory["entries"])).hexdigest()
    assert seal["inventory_sha256"] == hashlib.sha256(inventory_raw).hexdigest()
    assert seal["evidence_root_sha256"] == inventory["root_sha256"]
    assert seal["controller_sha256"] == sha(ROOT / "cleanup_controller.py")
    assert seal["v4_seal_sha256"] == sha(V4 / "SEAL.json")
    archive_sha, archive_entries = tree_digest(ARCHIVE)
    assert seal["archive_root_sha256"] == archive_sha
    assert json.loads((ROOT / "dry-run-receipt.json").read_text())["cleanup_replayed"] is False
    assert json.loads((ROOT / "controller-verification-receipt.json").read_text())["poststate"]["session_process_proof"]["target_processes"] == []
    result = {"schema": "task26-cleanup-v5-successor-seal-verification-v1", "status": "PASS", "evidence_entries": len(inventory["entries"]), "archive_entries": archive_entries, "archive_root_sha256": archive_sha, "v4_seal_sha256": seal["v4_seal_sha256"], "controller_sha256": seal["controller_sha256"], "process_finding_closed": True, "cleanup_replayed": False, "checks": len(inventory["entries"]) + 11}
    print(json.dumps(result, sort_keys=True, separators=(",", ":")))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
