#!/usr/bin/env python3
"""Create a sanitized GitHub source ZIP with one assetmanager/ root folder."""
from __future__ import annotations

import argparse
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile

ROOT = Path(__file__).resolve().parents[1]
EXCLUDED_NAMES = {
    ".git", ".venv", "venv", "__pycache__", ".pytest_cache", ".mypy_cache",
    ".ruff_cache", "dist", "THIRD_PARTY_LICENSES", ".internal",
}
EXCLUDED_FILES = {
    ".env",
    "data/config/config.json",
    "data/config/APPINFO.json",
    "app/main_old.py",
    "assetmanager.db",
    ".public-release-local-patterns",
    "AI_CONTENT.md", "AI_CONTENT_ANALYSE.txt", "AI_CONTEXT.md", "AI_CONTEXT_ANALYSE.txt",
    "DEVELOPMENT_NOTES.md", "DEVELOPMENT_CONTEXT.md",
}
RUNTIME_DIRS = {
    "data/postgres", "data/uploads", "data/logs", "data/backups",
    "data/backup", "data/scripts", "app/static/uploads",
}


def should_exclude(relative: Path) -> bool:
    posix = relative.as_posix()
    if any(part in EXCLUDED_NAMES for part in relative.parts):
        return True
    if posix in EXCLUDED_FILES:
        return True
    if relative.name.startswith(".env") and relative.name != ".env.example":
        return True
    if relative.suffix.lower() in {".db", ".sqlite", ".sqlite3", ".pyc", ".zip"}:
        return True
    return any(posix == directory or posix.startswith(directory + "/") for directory in RUNTIME_DIRS)


def copy_source(destination: Path) -> None:
    for source in ROOT.rglob("*"):
        relative = source.relative_to(ROOT)
        if should_exclude(relative):
            continue
        target = destination / relative
        if source.is_dir():
            target.mkdir(parents=True, exist_ok=True)
        elif source.is_file():
            target.parent.mkdir(parents=True, exist_ok=True)
            shutil.copy2(source, target)
    for directory in sorted(RUNTIME_DIRS):
        marker = destination / directory / ".gitkeep"
        marker.parent.mkdir(parents=True, exist_ok=True)
        marker.touch()


def make_zip(source_root: Path, output: Path) -> None:
    output.parent.mkdir(parents=True, exist_ok=True)
    with ZipFile(output, "w", compression=ZIP_DEFLATED, compresslevel=9) as archive:
        for path in sorted(source_root.rglob("*")):
            if path.is_file():
                archive.write(path, Path("assetmanager") / path.relative_to(source_root))


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--output", type=Path)
    args = parser.parse_args()
    version = (ROOT / "VERSION").read_text(encoding="utf-8").strip()
    output = (args.output or ROOT / "dist" / f"assetmanager-github-{version}.zip").resolve()

    with tempfile.TemporaryDirectory(prefix="assetmanager-public-") as temp_name:
        staged = Path(temp_name) / "assetmanager"
        staged.mkdir()
        copy_source(staged)
        checker = staged / "tools" / "check_public_release.py"
        command = [sys.executable, str(checker), "--root", str(staged)]
        denylist = ROOT / ".public-release-local-patterns"
        if denylist.is_file():
            command.extend(["--denylist", str(denylist)])
        result = subprocess.run(command)
        if result.returncode:
            print("GitHub ZIP was not created because the staged source failed validation.", file=sys.stderr)
            return result.returncode
        make_zip(staged, output)
    print(output)
    return 0


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