#!/usr/bin/env node
/**
 * Jalpi Page Builder — production ZIP packager.
 *
 * Copies the plugin to a temp directory (applying .distignore exclusions),
 * then creates a distribution ZIP suitable for WordPress.org or manual installs.
 *
 * Usage (from admin/editor/):
 *   npm run package
 *
 * Usage (from plugin root, requires Node.js ≥ 16):
 *   node bin/build-zip.js
 *
 * Output: dist/jalpi-page-builder.zip  (relative to plugin root)
 *
 * No extra npm packages required — uses only Node.js built-ins and the
 * platform's native zip tool (PowerShell on Windows, zip on Unix/macOS).
 */
'use strict';

const { cpSync, mkdirSync, rmSync, existsSync, statSync } = require('fs');
const { execSync } = require('child_process');
const path = require('path');
const os   = require('os');

// ─── Paths ────────────────────────────────────────────────────────────────────
// This script lives at  <plugin-root>/bin/build-zip.js
const PLUGIN_ROOT = path.resolve(__dirname, '..');
const PLUGIN_NAME = 'jalpi-page-builder';
const DIST_DIR    = path.join(PLUGIN_ROOT, 'dist');
const OUT_ZIP     = path.join(DIST_DIR, `${PLUGIN_NAME}.zip`);
const TMP_DIR     = path.join(os.tmpdir(), `${PLUGIN_NAME}-pack-${process.pid}`);
const TMP_DEST    = path.join(TMP_DIR, PLUGIN_NAME);

// ─── Exclusions (mirrors .distignore) ─────────────────────────────────────────
// Paths are resolved to absolute so the filter works regardless of cwd.
const EXCLUDE_ABS = [
  // Editor build-time assets
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'node_modules'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'src'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'package.json'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'package-lock.json'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'yarn.lock'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'pnpm-lock.yaml'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'build.js'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'webpack.config.js'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'vite.config.js'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'tsconfig.json'),
  path.join(PLUGIN_ROOT, 'admin', 'editor', 'jsconfig.json'),
  // Source control
  path.join(PLUGIN_ROOT, '.git'),
  path.join(PLUGIN_ROOT, '.gitignore'),
  path.join(PLUGIN_ROOT, '.gitattributes'),
  path.join(PLUGIN_ROOT, '.github'),
  // Tests. The Advanced Menu suites live OUTSIDE the WordPress install, in
  // <site>/dev-tests/, so plugin linters never scan them — these entries stay
  // as a guard in case a tests/ directory is ever added here.
  path.join(PLUGIN_ROOT, 'tests'),
  path.join(PLUGIN_ROOT, 'coverage'),
  // Linter config, if one is ever added — tooling, not plugin code.
  path.join(PLUGIN_ROOT, 'phpcs.xml.dist'),
  path.join(PLUGIN_ROOT, 'phpcs.xml'),
  // Packaging tools
  path.join(PLUGIN_ROOT, 'bin'),
  path.join(PLUGIN_ROOT, 'dist'),
  // Development notes / docs
  path.join(PLUGIN_ROOT, 'BUILD.md'),
  path.join(PLUGIN_ROOT, 'main-concept.txt'),
  path.join(PLUGIN_ROOT, 'woo.txt'),
  path.join(PLUGIN_ROOT, 'performance.txt'),
  path.join(PLUGIN_ROOT, 'plugin-checklist-audit.txt'),
  // Old ZIPs
  path.join(PLUGIN_ROOT, 'jalpi-page-builder.zip'),
  path.join(PLUGIN_ROOT, 'canvas-builder.zip'),
  // IDE / OS noise
  path.join(PLUGIN_ROOT, '.vscode'),
  path.join(PLUGIN_ROOT, '.idea'),
  path.join(PLUGIN_ROOT, '.claude'),
];

function shouldExclude(src) {
  const normalized = src.replace(/\\/g, '/');
  for (const excl of EXCLUDE_ABS) {
    const normalizedExcl = excl.replace(/\\/g, '/');
    if (normalized === normalizedExcl || normalized.startsWith(normalizedExcl + '/')) {
      return true;
    }
  }
  // Source maps
  if (src.endsWith('.map')) return true;
  return false;
}

// ─── Main ─────────────────────────────────────────────────────────────────────
console.log(`\n Jalpi Page Builder — production packager`);
console.log(`  Plugin root : ${PLUGIN_ROOT}`);
console.log(`  Output      : ${OUT_ZIP}\n`);

// Clean temp dir
if (existsSync(TMP_DIR)) rmSync(TMP_DIR, { recursive: true, force: true });
mkdirSync(TMP_DEST, { recursive: true });
mkdirSync(DIST_DIR, { recursive: true });

// Remove stale ZIP
if (existsSync(OUT_ZIP)) rmSync(OUT_ZIP);

// Copy with exclusions
console.log('  Copying files...');
cpSync(PLUGIN_ROOT, TMP_DEST, {
  recursive: true,
  filter: (src) => !shouldExclude(src),
});

// Create ZIP
console.log('  Creating ZIP...');
if (process.platform === 'win32') {
  execSync(
    `powershell -NoProfile -Command "Compress-Archive -Path '${TMP_DIR}\\*' -DestinationPath '${OUT_ZIP}'"`,
    { stdio: 'inherit' }
  );
} else {
  execSync(`cd "${TMP_DIR}" && zip -r "${OUT_ZIP}" "${PLUGIN_NAME}"`, {
    stdio: 'inherit',
    shell: '/bin/bash',
  });
}

// Clean up temp dir
rmSync(TMP_DIR, { recursive: true, force: true });

// Report
const { size } = statSync(OUT_ZIP);
const sizeMB = (size / 1024 / 1024).toFixed(2);
console.log(`\n  Done!`);
console.log(`  ${OUT_ZIP}`);
console.log(`  ${sizeMB} MB\n`);
