/**
 * Emit the extension and self-host app zips as STATIC files under
 * web/dist/api/, mirroring the local server's dynamic /api/extension.zip and
 * /api/app.zip routes. On Cloudflare Pages there is no server — without these,
 * the SPA fallback serves HTML at those paths and the "zip" downloads corrupt.
 * Locally the Express routes win (registered before static), so behavior there
 * is unchanged. Runs AFTER vite build (vite empties web/dist).
 */
import { execFileSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const OUT_DIR = path.join(ROOT, 'web', 'dist', 'api');
const EXT_DIR = path.join(ROOT, 'extension');

/** LOCKSTEP: both patchers must embed the same LOGIC_VERSION constant. */
function assertPatcherLogicVersionsMatch(): void {
  const sh = fs.readFileSync(path.join(EXT_DIR, 'MacOS-Linux-Plugin-Patcher.sh'), 'utf8');
  const ps1 = fs.readFileSync(path.join(EXT_DIR, 'Windows-Plugin-Patcher.ps1'), 'utf8');
  const shM = /^LOGIC_VERSION="([^"]+)"/m.exec(sh);
  const psM = /^\$LOGIC_VERSION\s*=\s*'([^']+)'/m.exec(ps1);
  if (!shM) throw new Error('MacOS-Linux-Plugin-Patcher.sh missing LOGIC_VERSION="…"');
  if (!psM) throw new Error('Windows-Plugin-Patcher.ps1 missing $LOGIC_VERSION = \'…\'');
  if (shM[1] !== psM[1]) {
    throw new Error(
      `Patcher LOGIC_VERSION mismatch: sh=${shM[1]} ps1=${psM[1]} — update both in the same commit`,
    );
  }
  // eslint-disable-next-line no-console
  console.log(`patcher LOGIC_VERSION lockstep ok: ${shM[1]}`);
}

fs.mkdirSync(OUT_DIR, { recursive: true });
assertPatcherLogicVersionsMatch();

// Same exclusions as the server's /api/extension.zip route.
// Includes MacOS-Linux-Plugin-Patcher.sh + Windows-Plugin-Patcher.ps1 at zip root.
execFileSync('zip', ['-qr', path.join(OUT_DIR, 'extension.zip'), '.', '-x', 'node_modules/*', '-x', '.DS_Store'], {
  cwd: EXT_DIR,
  timeout: 30_000,
});

// Same exclusions as the server's /api/app.zip route, plus web/dist/api/*
// so the app bundle never nests these zips inside itself.
execFileSync('zip', [
  '-qr', path.join(OUT_DIR, 'app.zip'), '.',
  '-x', 'node_modules/*', '-x', '*/node_modules/*',
  '-x', '.git/*', '-x', 'workspaces/*', '-x', 'data/*',
  '-x', '.env', '-x', '*.log', '-x', '.DS_Store', '-x', '*/.DS_Store',
  '-x', 'web/public/landing.html', '-x', 'web/public/privacy.html',
  '-x', 'web/dist/api/*',
], { cwd: ROOT, timeout: 120_000 });

// Publish the bundled extension version at the SAME path the app already
// queries on the local engine (/api/extension/meta): the hosted site's
// version-mismatch banner — the product's own self-update mechanism — needs
// this to detect stale installs. Without it, production never tells anyone
// their Provider Vault is outdated.
const manifest = JSON.parse(fs.readFileSync(path.join(ROOT, 'extension', 'manifest.json'), 'utf8')) as { version: string };
const metaDir = path.join(OUT_DIR, 'extension');
fs.mkdirSync(metaDir, { recursive: true });
fs.writeFileSync(path.join(metaDir, 'meta'), JSON.stringify({ version: manifest.version }));
// eslint-disable-next-line no-console
console.log(`web/dist/api/extension/meta: version ${manifest.version}`);

for (const f of ['extension.zip', 'app.zip']) {
  const bytes = fs.statSync(path.join(OUT_DIR, f)).size;
  // eslint-disable-next-line no-console
  console.log(`web/dist/api/${f}: ${(bytes / 1024 / 1024).toFixed(1)} MB`);
  if (bytes > 24 * 1024 * 1024) {
    throw new Error(`${f} exceeds Cloudflare Pages' 25 MB per-file limit`);
  }
}
