#!/usr/bin/env python3
"""Verify finish_ready/HASH_MANIFEST.json.

The manifest lists sha256 and sizes for all release files (excluding itself and
submission_bundle.zip). This script recomputes hashes and verifies exact match.

Exit status:
- 0 on success
- 1 on any mismatch
"""

import hashlib
import json
import sys
from pathlib import Path


def sha256_file(p: Path) -> str:
    h = hashlib.sha256()
    with p.open('rb') as f:
        for chunk in iter(lambda: f.read(1024 * 1024), b''):
            h.update(chunk)
    return h.hexdigest()


def fail(msg: str) -> None:
    print("FAIL:", msg)
    sys.exit(1)


def main() -> None:
    here = Path(__file__).resolve().parent
    root = (here / "..").resolve()  # finish_ready/
    manifest_path = (root / "HASH_MANIFEST.json").resolve()
    if not manifest_path.exists():
        fail(f"Missing manifest: {manifest_path}")

    m = json.loads(manifest_path.read_text(encoding="utf-8"))
    files = m.get("files", [])
    if not isinstance(files, list) or not files:
        fail("Manifest has no files")

    bad = 0
    for it in files:
        rel = it.get("path", "")
        expect_h = it.get("sha256", "")
        expect_n = it.get("bytes", None)
        if not rel or not expect_h or expect_n is None:
            fail(f"Bad manifest entry: {it!r}")
        p = (root / rel).resolve()
        if not p.exists():
            bad += 1
            print("MISSING:", rel)
            continue
        got_n = p.stat().st_size
        if got_n != int(expect_n):
            bad += 1
            print("SIZE MISMATCH:", rel, "got", got_n, "expected", expect_n)
        got_h = sha256_file(p)
        if got_h != expect_h:
            bad += 1
            print("HASH MISMATCH:", rel)
            print("  got     ", got_h)
            print("  expected", expect_h)

    if bad:
        fail(f"Integrity check failed: {bad} issue(s)")

    print("OK: HASH_MANIFEST verified")


if __name__ == "__main__":
    main()
