"""Build a deterministic public-safe archive from explicit package directories.

Run after source extraction/reproduction/testing. Does not publish or access a network.
The archive excludes output work directories, environments, caches and private audits.
"""
import argparse
import hashlib
import json
from pathlib import Path
import zipfile

root = Path(__file__).resolve().parents[1]
parser = argparse.ArgumentParser()
parser.add_argument("--out", type=Path, required=True, help="Directory outside the package for the ZIP and checksum")
args = parser.parse_args()
out = args.out.resolve()
if out.is_relative_to(root):
    parser.error("Archive output must be outside the source package.")
names = ["README.md", "LICENSE", "DATA-LICENSE.md", "CITATION.cff", ".gitignore"]
directories = ["ligninqc", "data", "docs", "examples", "tests", "tools", "reference"]
files = [root / name for name in names]
for directory in directories:
    files.extend(p for p in (root / directory).rglob("*") if p.is_file() and "__pycache__" not in p.parts and p.suffix != ".pyc")
for p in files:
    if p.is_symlink() or not p.is_file():
        parser.error(f"Expected a real package file: {p.relative_to(root)}")
files = sorted(set(files))
manifest = {"schema_version": 1, "software_version": "1.0.0", "sha256": {str(p.relative_to(root)): hashlib.sha256(p.read_bytes()).hexdigest() for p in files}}
manifest_path = root / "manifest.json"
manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
files.append(manifest_path)
out.mkdir(parents=True, exist_ok=True)
stem = "ligninqc-reanalysis-2026-09-05"
archive = out / (stem + ".zip")
with zipfile.ZipFile(archive, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as z:
    for p in sorted(files):
        info = zipfile.ZipInfo(stem + "/" + p.relative_to(root).as_posix(), date_time=(2026, 9, 5, 0, 0, 0))
        info.compress_type = zipfile.ZIP_DEFLATED
        info.external_attr = 0o100644 << 16
        info.create_system = 3
        z.writestr(info, p.read_bytes(), compress_type=zipfile.ZIP_DEFLATED, compresslevel=9)
checksum = hashlib.sha256(archive.read_bytes()).hexdigest()
(out / "SHA256SUMS").write_text(f"{checksum}  {archive.name}\n", encoding="ascii")
print(json.dumps({"archive": str(archive), "sha256": checksum, "file_count": len(files), "bytes": archive.stat().st_size}, indent=2))
