"""Build the public corresponding-source tree from an explicit allowlist."""
from pathlib import Path
import shutil

ROOT=Path(__file__).resolve().parent
TOP=("README.md","REVIEW.md","NOTICE.md","LICENSE","requirements.txt","requirements-test.txt",
     "requirements-lock.txt","package.json","check.sh","prepare_source.py")
DIRECTORIES={"backend":(".py",),"public":(".html",),"public/assets":(".css",".js",".json"),
             "tests":(".py",".js"),"deploy":(".conf",".service",".example")}


def source_files():
    paths=[ROOT/name for name in TOP]
    for directory,suffixes in DIRECTORIES.items():
        paths.extend(p for p in sorted((ROOT/directory).iterdir()) if p.is_file() and p.suffix in suffixes)
    for path in paths:
        if not path.is_file() or path.is_symlink():
            raise RuntimeError(f"Missing or unsafe source file: {path.relative_to(ROOT)}")
    return paths


if __name__=="__main__":
    target=ROOT/"public/source"
    if target.is_symlink():
        raise RuntimeError("Refusing a symlinked source destination")
    files=source_files()
    # Refuse unexpected stale files rather than silently publishing them.
    expected={p.relative_to(ROOT) for p in files}
    if target.exists():
        extras=[p for p in target.rglob("*") if p.is_file() and p.relative_to(target) not in expected]
        if extras:
            raise RuntimeError("Unexpected files in public/source; inspect them before rebuilding.")
    for path in files:
        output=target/path.relative_to(ROOT)
        output.parent.mkdir(parents=True,exist_ok=True)
        if output.is_symlink() or any(parent.is_symlink() for parent in output.parents if parent!=ROOT):
            raise RuntimeError("Refusing a symlinked source path")
        shutil.copyfile(path,output)
        output.chmod(0o644)
    print(f"Prepared {len(files)} source files; no credentials or runtime dependencies copied.")
