<?php
declare(strict_types=1);

$cfg = require __DIR__ . '/../blogger_api/config.php';
$tenantsDir = rtrim((string)($cfg['tenants_dir'] ?? '/home/mytown/blog.mytown.ink/tenants'), '/');

function read_json(string $path): ?array {
  if (!is_file($path)) return null;
  $raw = file_get_contents($path);
  if ($raw === false) return null;
  $d = json_decode($raw, true);
  return is_array($d) ? $d : null;
}

function write_json_atomic(string $path, array $data, int $mode = 0640): bool {
  $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
  if ($json === false) return false;
  $tmp = $path . '.tmp';
  if (file_put_contents($tmp, $json, LOCK_EX) === false) return false;
  @chmod($tmp, $mode);
  return @rename($tmp, $path);
}

function log_download(string $msg, array $cfg): void {
  $log = (string)($cfg['download_log'] ?? '');
  if ($log === '') return;
  @file_put_contents($log, '[' . date('c') . '] ' . $msg . "\n", FILE_APPEND);
}

$ref = trim((string)($_GET['ref'] ?? ''));
$token = trim((string)($_GET['token'] ?? ''));

if ($ref === '' || $token === '') {
  http_response_code(400);
  echo 'Missing ref or token';
  exit;
}

if (!preg_match('/^t_[a-f0-9]{16}$/', $ref)) {
  http_response_code(400);
  echo 'Invalid ref format';
  exit;
}

if (!preg_match('/^[a-f0-9]{32}$/', $token)) {
  http_response_code(400);
  echo 'Invalid token format';
  exit;
}

$tenantDir  = $tenantsDir . '/' . $ref;
$envPath    = $tenantDir . '/.env';
$activePath = $tenantDir . '/active.json';

if (!is_dir($tenantDir) || !is_file($envPath) || !is_file($activePath)) {
  http_response_code(404);
  echo 'Not found';
  exit;
}

$templateKit = (string)($cfg['kit_zip_path'] ?? '/home/mytown/blog.mytown.ink/assets/blogger-kit.zip');
if (!is_file($templateKit) || filesize($templateKit) < 1024) {
  http_response_code(500);
  echo 'Kit missing on server';
  exit;
}

// Concurrency guard: one download at a time per tenant.
$lockPath = $activePath . '.lock';
$lockFp = fopen($lockPath, 'c');
if (!$lockFp) {
  http_response_code(500);
  echo 'Server lock error';
  exit;
}

if (!flock($lockFp, LOCK_EX)) {
  fclose($lockFp);
  http_response_code(500);
  echo 'Server lock error';
  exit;
}

// Re-read active.json under lock
$active = read_json($activePath);
if (!is_array($active) || strtolower((string)($active['status'] ?? '')) !== 'active') {
  flock($lockFp, LOCK_UN);
  fclose($lockFp);
  http_response_code(403);
  echo 'Not active';
  exit;
}

$download = is_array($active['download'] ?? null) ? $active['download'] : [];
$currentToken = (string)($download['token'] ?? '');

if ($currentToken === '' || !hash_equals($currentToken, $token)) {
  flock($lockFp, LOCK_UN);
  fclose($lockFp);
  http_response_code(403);
  echo 'Invalid token';
  log_download('denied_invalid_token ref=' . $ref, $cfg);
  exit;
}

// Build a personalized kit zip (copy template, then inject files)
$tmpDir = sys_get_temp_dir();
$tmpKit = rtrim($tmpDir, '/') . '/Blogger-Kit-' . $ref . '-' . bin2hex(random_bytes(4)) . '.zip';

$cleanup = function() use ($tmpKit) {
  if (is_file($tmpKit)) @unlink($tmpKit);
};
register_shutdown_function($cleanup);

if (!@copy($templateKit, $tmpKit)) {
  flock($lockFp, LOCK_UN);
  fclose($lockFp);
  http_response_code(500);
  echo 'Failed to prepare kit';
  log_download('kit_copy_failed ref=' . $ref, $cfg);
  exit;
}

$envContent = (string)(file_get_contents($envPath) ?: '');

$zip = new ZipArchive();
$openRes = $zip->open($tmpKit);
if ($openRes !== true) {
  flock($lockFp, LOCK_UN);
  fclose($lockFp);
  http_response_code(500);
  echo 'Failed to open kit';
  log_download('kit_zip_open_failed ref=' . $ref . ' code=' . (string)$openRes, $cfg);
  exit;
}

// Inject .env only (no extra license breadcrumbs)
// Put it in the kit root AND inside bootstrap_kit/ for convenience.
$zip->addFromString('.env', $envContent !== '' ? $envContent : "TENANT_REF={$ref}\n");
$zip->addFromString('bootstrap_kit/.env', $envContent !== '' ? $envContent : "TENANT_REF={$ref}\n");


// Helper files for humans (optional, but makes support easy)
$zip->addFromString('MY_ENV.txt', $envContent !== '' ? $envContent : "TENANT_REF={$ref}\n");
$zip->addFromString('TENANT_REF.txt', $ref . "\n");
if (preg_match('/^LICENSE_KEY=(.+)$/m', $envContent, $mm)) {
  $zip->addFromString('LICENSE_KEY.txt', trim($mm[1]) . "\n");
}
$zip->close();

// Rotate token now that we have a valid kit prepared
$newToken = bin2hex(random_bytes(16));
$active['download'] = array_merge($download, [
  'token' => $newToken,
  'token_issued_at' => date('c'),
  'last_token' => $currentToken,
  'last_used_at' => date('c'),
  'last_used_ip' => (string)($_SERVER['REMOTE_ADDR'] ?? ''),
  'last_used_ua' => (string)($_SERVER['HTTP_USER_AGENT'] ?? ''),
]);

if (!write_json_atomic($activePath, $active, 0640)) {
  flock($lockFp, LOCK_UN);
  fclose($lockFp);
  http_response_code(500);
  echo 'Failed to finalize download';
  log_download('active_write_failed ref=' . $ref, $cfg);
  exit;
}

flock($lockFp, LOCK_UN);
fclose($lockFp);

log_download('served ref=' . $ref, $cfg);

// Stream the personalized kit
$filename = 'Blogger-Kit-' . $ref . '.zip';

header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . filesize($tmpKit));
header('X-Content-Type-Options: nosniff');

$fp = fopen($tmpKit, 'rb');
if (!$fp) {
  http_response_code(500);
  echo 'Cannot read kit';
  exit;
}

fpassthru($fp);
fclose($fp);

// Cleanup
@unlink($tmpKit);
exit;
