/**
 * Invoked by blue: node bundle.mjs <entryAbs> <projectRootAbs> <outfileAbs> [platform]
 *
 * Full npm bundling for QuickJS island:
 *  - Uses esbuild's native bundler output (no primitive-only stitch)
 *  - Produces one JS file to evaluate in QuickJS
 *  - Leaves Node builtins external for runtime `require()` bridge
 */
import * as esbuild from "esbuild";
import fs from "fs";
import path from "path";

const argv = process.argv.slice(2);
const entry = argv[0];
const absWorkingDir = argv[1];
const outfile = argv[2];
const platformArg = argv[3] || "neutral";

if (!entry || !absWorkingDir || !outfile) {
  console.error(
    "blue-npm-bundle: usage: node bundle.mjs <entry> <cwd> <outfile> [platform]"
  );
  process.exit(2);
}

const platforms = new Set(["neutral", "browser", "node"]);
const platform = platforms.has(platformArg) ? platformArg : "neutral";

if (!fs.existsSync(entry)) {
  console.error("blue-npm-bundle: entry not found:", entry);
  process.exit(1);
}
if (!fs.existsSync(absWorkingDir)) {
  console.error("blue-npm-bundle: project root not found:", absWorkingDir);
  process.exit(1);
}

const entryAbs = path.resolve(entry);
const rootAbs = path.resolve(absWorkingDir);
const outPath = path.resolve(outfile);
const entryLabel =
  path.relative(rootAbs, entryAbs).replace(/\\/g, "/") || path.basename(entryAbs);

const builtins = [
  "fs", "path", "os", "process", "buffer", "events", "util", "assert",
  "url", "querystring", "stream", "crypto", "http", "https", "net", "tls",
  "zlib", "tty", "dns", "timers", "module"
];
const forceExternal = ["express"];
const strictNative = process.env.BLUE_STRICT_NATIVE === "1";
const warnedUnknownPackages = new Set();
const warnedNativeAddons = new Set();

function packageNameFromSpecifier(spec) {
  if (!spec) return "";
  if (spec.startsWith("@")) {
    const parts = spec.split("/");
    return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : spec;
  }
  const idx = spec.indexOf("/");
  return idx >= 0 ? spec.slice(0, idx) : spec;
}

const nativeAddonWarningPlugin = {
  name: "blue-native-addon-warning",
  setup(build) {
    build.onResolve({ filter: /\.node$/ }, (args) => {
      const key = `${args.importer}::${args.path}`;
      const pkg = packageNameFromSpecifier(args.path);
      const msg =
        "⚠️ Blue Compatibility Warning: Native C++ Addon Detected\n" +
        `The package "${pkg || args.path}" relies on a Node.js native binding (.node). QuickJS does not support V8 C++ bindings.\n` +
        `Importer: ${args.importer || "<entry>"}\n` +
        `Path: ${args.path}\n` +
        'The Fix: This package will likely crash at runtime. Please use a pure-JavaScript alternative (e.g., "bcryptjs").';

      if (strictNative) {
        return { errors: [{ text: msg }] };
      }
      if (!warnedNativeAddons.has(key)) {
        warnedNativeAddons.add(key);
        console.warn(msg);
      }
      return null;
    });

    build.onResolve({ filter: /^[^./]|^\@/ }, (args) => {
      const spec = args.path || "";
      if (!spec || spec.startsWith("node:") || builtins.includes(spec)) return null;
      if (forceExternal.includes(spec)) return null;
      /* Browser bundles (e.g. React app.bundle.js) run in the embedded WebView, not QuickJS. */
      if (platform === "browser") return null;
      if (args.importer !== entryAbs) return null;
      const pkg = packageNameFromSpecifier(spec);
      if (!pkg || warnedUnknownPackages.has(pkg)) return null;
      warnedUnknownPackages.add(pkg);
      console.warn(
        "⚠️ Blue Compatibility Warning: Island package compatibility unknown\n" +
          `The package "${pkg}" was imported from "${entryLabel}". Compatibility may not work in QuickJS runtime shims.\n` +
          "The Fix: Verify this dependency in acceptance tests and prefer pure-JS packages when possible."
      );
      return null;
    });
  }
};

try {
  await esbuild.build({
    entryPoints: [entryAbs],
    absWorkingDir: rootAbs,
    bundle: true,
    outfile: outPath,
    write: true,
    format: "iife",
    platform: platform === "browser" ? "browser" : "node",
    target: ["es2020"],
    packages: "bundle",
    external: builtins.concat(builtins.map((x) => "node:" + x)).concat(forceExternal),
    plugins: [nativeAddonWarningPlugin],
    logLevel: "warning",
    banner: {
      js:
        "var module={exports:{}};var exports=module.exports;" +
        "if(typeof global==='undefined')global=globalThis;" +
        "if(typeof globalThis.__dirname==='undefined')globalThis.__dirname='.';" +
        "if(typeof globalThis.__filename==='undefined')globalThis.__filename='main.js';"
    },
    // Island → __BLUE_ISLAND; C++ then sets globalThis.Blue (jsc_hybrid_runtime.cpp)
    footer: {
      js:
        "if(module&&module.exports&&typeof module.exports==='object'){" +
        "if(!globalThis.__BLUE_ISLAND)globalThis.__BLUE_ISLAND={};" +
        "for(var k in module.exports){globalThis.__BLUE_ISLAND[k]=module.exports[k];}" +
        "if(typeof module.exports==='function'){globalThis.__BLUE_ISLAND.default=module.exports;}" +
        "}"
    }
  });
} catch (e) {
  console.error("blue-npm-bundle:", e?.message || e);
  process.exit(1);
}
