<?php
declare(strict_types=1);

if (PHP_SAPI !== 'cli') {
  http_response_code(404);
  exit;
}

$projectRoot = realpath(__DIR__ . '/../..');
if (!$projectRoot || !is_file($projectRoot . '/index.php') || !is_dir($projectRoot . '/code')) {
  fwrite(STDERR, "Run this from inside the project tree.\n");
  exit(1);
}

$zipBin = trim((string)shell_exec('command -v zip 2>/dev/null'));
if ($zipBin === '') {
  fwrite(STDERR, "Missing zip command.\n");
  exit(1);
}

$releaseDir = $projectRoot . '/code/releases';
if (!is_dir($releaseDir)) @mkdir($releaseDir, 0775, true);
$stamp = date('Ymd-His');
$zipPath = $releaseDir . '/manager-release-' . $stamp . '.zip';
$stage = sys_get_temp_dir() . '/ysp-release-' . $stamp . '-' . bin2hex(random_bytes(3));

function release_skip(string $relative): bool {
  $relative = str_replace('\\', '/', $relative);
  if ($relative === '') return false;
  $parts = explode('/', $relative);
  $base = basename($relative);
  if (in_array($parts[0], ['.data', '.manager-saves', '.manager-save-backups', 'releases'], true)) return true;
  if ($parts[0] === 'uploads' && ($parts[1] ?? '') === 'manager-chat') return true;
  if ($parts[0] === 'reports' && count($parts) > 1) return true;
  if ($relative === 'touchlines/node_modules' || str_starts_with($relative, 'touchlines/node_modules/')) return true;
  if (preg_match('/^\\.state(?:\\.|$)|^\\.state\\.lock$|^\\.manager\\.log$|^\\.client-debug\\.log$/', $base)) return true;
  return false;
}

function release_copy_tree(string $source, string $target, string $prefix = ''): void {
  if (!is_dir($target)) @mkdir($target, 0775, true);
  if (is_dir($target)) @chmod($target, 0755);
  $items = scandir($source);
  if (!is_array($items)) return;
  foreach ($items as $item) {
    if ($item === '.' || $item === '..') continue;
    $relative = ltrim($prefix . '/' . $item, '/');
    if (release_skip($relative)) continue;
    $from = $source . '/' . $item;
    $to = $target . '/' . $item;
    if (is_dir($from)) {
      release_copy_tree($from, $to, $relative);
    } elseif (is_file($from)) {
      if (!is_dir(dirname($to))) @mkdir(dirname($to), 0775, true);
      copy($from, $to);
      @chmod($to, 0644);
    }
  }
}

function release_normalize_permissions(string $path): void {
  if (is_dir($path)) {
    @chmod($path, 0755);
    $items = scandir($path);
    if (!is_array($items)) return;
    foreach ($items as $item) {
      if ($item === '.' || $item === '..') continue;
      release_normalize_permissions($path . '/' . $item);
    }
    return;
  }
  if (is_file($path)) @chmod($path, 0644);
}

function release_prepare_runtime_dirs(string $codeStage): void {
  $dirs = [
    $codeStage . '/.data',
    $codeStage . '/.manager-saves',
    $codeStage . '/.manager-saves/.meta',
    $codeStage . '/.manager-save-backups',
    $codeStage . '/uploads',
    $codeStage . '/uploads/manager-chat',
    $codeStage . '/reports',
  ];
  foreach ($dirs as $dir) {
    if (!is_dir($dir)) @mkdir($dir, 0777, true);
    if (is_dir($dir)) @chmod($dir, 0777);
  }
}

function release_remove_tree(string $path): void {
  if (!is_dir($path)) return;
  $items = scandir($path);
  if (is_array($items)) {
    foreach ($items as $item) {
      if ($item === '.' || $item === '..') continue;
      $child = $path . '/' . $item;
      if (is_dir($child)) release_remove_tree($child);
      else @unlink($child);
    }
  }
  @rmdir($path);
}

@mkdir($stage, 0775, true);
copy($projectRoot . '/index.php', $stage . '/index.php');
copy($projectRoot . '/code/tools/install.template.php', $stage . '/install.php');
release_copy_tree($projectRoot . '/code', $stage . '/code');
release_normalize_permissions($stage);
release_prepare_runtime_dirs($stage . '/code');

$cmd = 'cd ' . escapeshellarg($stage) . ' && ' . escapeshellarg($zipBin) . ' -X -qr ' . escapeshellarg($zipPath) . ' index.php install.php code';
exec($cmd, $out, $code);
release_remove_tree($stage);
if ($code !== 0 || !is_file($zipPath)) {
  fwrite(STDERR, "Zip build failed.\n");
  exit(1);
}
@chmod($zipPath, 0666);
echo $zipPath . PHP_EOL;
