#!/usr/bin/env python3
"""Build a byte-reproducible ZIP archive from a release directory."""

from __future__ import annotations

import argparse
import os
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo

FIXED_TIMESTAMP = (1980, 1, 1, 0, 0, 0)


def iter_files(source: Path):
    for path in sorted(source.rglob("*"), key=lambda item: item.as_posix()):
        if path.is_file() and not path.is_symlink():
            yield path


def build_archive(source: Path, destination: Path) -> None:
    source = source.resolve(strict=True)
    if not source.is_dir():
        raise ValueError(f"Source is not a directory: {source}")
    destination = destination.resolve()
    if source == destination or source in destination.parents:
        raise ValueError("Destination must be outside the source directory.")

    destination.parent.mkdir(parents=True, exist_ok=True)
    temporary = destination.with_suffix(destination.suffix + ".tmp")
    temporary.unlink(missing_ok=True)

    try:
        with ZipFile(temporary, "w", compression=ZIP_DEFLATED, compresslevel=9) as archive:
            for file_path in iter_files(source):
                relative = file_path.relative_to(source.parent).as_posix()
                info = ZipInfo(relative, FIXED_TIMESTAMP)
                info.compress_type = ZIP_DEFLATED
                info.create_system = 3
                mode = file_path.stat().st_mode & 0o777
                info.external_attr = (mode & 0xFFFF) << 16
                info.flag_bits |= 0x800
                archive.writestr(info, file_path.read_bytes(), compress_type=ZIP_DEFLATED, compresslevel=9)
        os.replace(temporary, destination)
    finally:
        temporary.unlink(missing_ok=True)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("source", type=Path)
    parser.add_argument("destination", type=Path)
    args = parser.parse_args()
    build_archive(args.source, args.destination)
    print(f"Deterministic ZIP created: {args.destination}")
    return 0


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