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

This manifest is intended as a practical integrity index for a release folder.
To avoid self-referential hashing, the manifest does NOT include entries for:
- HASH_MANIFEST.json itself
- submission_bundle.zip (the bundle is derived from the folder)

All other files under finish_ready/ are listed with relative path, sha256, and size.
"""

import hashlib
import json
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 main() -> None:
    root = Path(__file__).resolve().parent
    out_path = root / 'HASH_MANIFEST.json'

    files = []
    for p in sorted(root.rglob('*')):
        if p.is_dir():
            continue
        rel = p.relative_to(root).as_posix()
        # Exclude transient build outputs and logs to keep integrity indices stable across machines.
        if rel.startswith('scripts/build') or rel.startswith('scripts/build_') or rel.startswith('scripts/builds'):
            continue
        if rel.startswith('scripts/build_atlas') or rel.startswith('scripts/build_global') or rel.startswith('scripts/build_sft'):
            continue
        if rel.endswith(('.log', '.aux', '.out', '.toc', '.synctex.gz')):
            continue
        if rel in ('HASH_MANIFEST.json', 'submission_bundle.zip'):
            continue
        files.append({
            'path': rel,
            'sha256': sha256_file(p),
            'bytes': p.stat().st_size,
        })

    manifest = {
        'bundle': 'submission_bundle',
        'version': (root / 'VERSION.txt').read_text(encoding='utf-8').strip(),
        'generated_by': 'hash_manifest_regen.py',
        'file_count': len(files),
        'files': files,
    }

    out_path.write_text(json.dumps(manifest, indent=2) + '\n', encoding='utf-8')


if __name__ == '__main__':
    main()
