#!/usr/bin/env python3
"""Verify every downloaded VLCKit tool/contrib archive against VideoLAN SHA512SUMS."""

from __future__ import annotations

import argparse
import hashlib
import re
import subprocess
import sys
from pathlib import Path

ARCHIVE_SUFFIXES = (".tar.gz", ".tar.bz2", ".tar.xz", ".tgz", ".zip")
SUM_RE = re.compile(r"^([0-9a-fA-F]{128})[ \t]+[*]?(.+?)$")
FORBIDDEN_CONTRIB_SOURCE_TOKENS = ("zvbi",)


def reject_forbidden_download(path: Path) -> None:
    if path.parent.name == "tarballs" and any(
        token in path.name.lower() for token in FORBIDDEN_CONTRIB_SOURCE_TOKENS
    ):
        raise ValueError(f"forbidden contrib source archive was fetched: {path}")


def sha512(path: Path) -> str:
    digest = hashlib.sha512()
    with path.open("rb") as source:
        for block in iter(lambda: source.read(1024 * 1024), b""):
            digest.update(block)
    return digest.hexdigest()


def load_catalogs(vlc_root: Path) -> dict[str, set[str]]:
    catalog: dict[str, set[str]] = {}
    files = [
        vlc_root / "extras/tools/SHA512SUMS",
        *sorted((vlc_root / "contrib/src").rglob("SHA512SUMS")),
    ]
    for checksum_file in files:
        if checksum_file.is_symlink() or not checksum_file.is_file():
            raise ValueError(f"missing or symlinked checksum catalog: {checksum_file}")
        for raw in checksum_file.read_text(encoding="utf-8").splitlines():
            match = SUM_RE.fullmatch(raw.strip())
            if match:
                digest, filename = match.groups()
                catalog.setdefault(Path(filename).name, set()).add(digest.lower())
    return catalog


def audit(vlc_root: Path, destination: Path) -> None:
    catalog = load_catalogs(vlc_root)
    candidates = [
        *sorted((vlc_root / "extras/tools").iterdir()),
        *sorted((vlc_root / "contrib/tarballs").iterdir()),
    ]
    archives = [path for path in candidates if path.name.endswith(ARCHIVE_SUFFIXES)]
    if not archives:
        raise ValueError("no downloaded tool/contrib archives were found")
    rows: list[str] = []
    for archive in archives:
        reject_forbidden_download(archive)
        if archive.is_symlink() or not archive.is_file():
            raise ValueError(f"downloaded source archive must be regular and non-symlink: {archive}")
        expected = catalog.get(archive.name, set())
        if len(expected) != 1:
            raise ValueError(f"{archive.name} has {len(expected)} authoritative SHA-512 values")
        actual = sha512(archive)
        if actual not in expected:
            raise ValueError(f"SHA-512 mismatch for {archive}: {actual}")
        rows.append(f"{archive.relative_to(vlc_root).as_posix()}\t{actual}")
    destination.parent.mkdir(parents=True, exist_ok=True)
    destination.write_text(
        "archive\tsha512\n" + "".join(f"{row}\n" for row in sorted(rows)), encoding="utf-8"
    )


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--vlc-root", required=True, type=Path)
    parser.add_argument("--output", required=True, type=Path)
    args = parser.parse_args()
    try:
        audit(args.vlc_root.resolve(), args.output.resolve())
    except (OSError, ValueError, subprocess.CalledProcessError) as error:
        print(f"ERROR: {error}", file=sys.stderr)
        return 1
    return 0


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