#!/usr/bin/env python3
"""
Build the deployment zip.

Use this rather than PowerShell's Compress-Archive. On Windows PowerShell 5.1
Compress-Archive writes zip entries with BACKSLASH path separators, which the
ZIP spec does not allow. Linux extractors handle that inconsistently: cPanel's
File Manager produced directory entries with 1970 timestamps that could not be
opened, listed or deleted, and the app silently lost its stylesheet.

    python tools/build-package.py

Writes ../lotto-syndicate-app-deploy.zip and verifies it afterwards.

Excluded from the package, deliberately:
  app/config.php       server passwords, written fresh on each server
  public/uploads/*     member ticket photos, must never be redistributed
  .git, *.log          not wanted on the server
"""

import os
import sys
import zipfile

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
OUT = os.path.join(os.path.dirname(ROOT), 'lotto-syndicate-app-deploy.zip')

SKIP_DIRS = {'.git', '.github', 'node_modules', '__pycache__'}
SKIP_FILES = {'app/config.php'}
KEEP_IN_UPLOADS = {'.htaccess', '.gitkeep'}


def included(rel: str) -> bool:
    if rel in SKIP_FILES:
        return False
    if rel.endswith('.log'):
        return False
    # Ticket photos are member data. Keep the folders and their guards only.
    if rel.startswith('public/uploads/'):
        return os.path.basename(rel) in KEEP_IN_UPLOADS
    return True


def main() -> int:
    entries = []

    with zipfile.ZipFile(OUT, 'w', zipfile.ZIP_DEFLATED) as z:
        for base, dirs, files in os.walk(ROOT):
            dirs[:] = sorted(d for d in dirs if d not in SKIP_DIRS)
            for name in sorted(files):
                full = os.path.join(base, name)
                # Forward slashes, always - this is the whole point.
                rel = os.path.relpath(full, ROOT).replace(os.sep, '/')
                if not included(rel):
                    continue
                z.write(full, rel)
                entries.append(rel)

    # Verify rather than trust.
    problems = []
    with zipfile.ZipFile(OUT) as z:
        names = z.namelist()

        backslashed = [n for n in names if '\\' in n]
        if backslashed:
            problems.append('%d entries use backslash separators' % len(backslashed))

        if z.testzip() is not None:
            problems.append('archive failed its integrity check')

        for required in ('app/.htaccess', 'public/.htaccess', 'public/uploads/.htaccess',
                         'public/assets/css/app.css', 'public/assets/js/app.js',
                         'public/index.php', 'schema.sql'):
            if required not in names:
                problems.append('missing ' + required)

        for forbidden in ('app/config.php',):
            if forbidden in names:
                problems.append('LEAKED ' + forbidden)

    print('%s\n%d entries, %.1f KB' % (OUT, len(entries), os.path.getsize(OUT) / 1024))

    if problems:
        print('\nPROBLEMS:')
        for p in problems:
            print('  - ' + p)
        return 1

    print('Verified: forward slashes, integrity OK, guards present, no config.php.')
    return 0


if __name__ == '__main__':
    sys.exit(main())
