#!/usr/bin/env node
'use strict';

/**
 * build-bundle.mjs — reproducible bundle build (Trust Hygiene H2).
 *
 * `gen-context.js` is composed of three parts:
 *   1. preamble       — the `__require` lazy-module loader (fixed)
 *   2. bundled modules — a sorted, de-duplicated copy of every `src/*.js`
 *                        module, embedded as `__factories[...]` blocks
 *   3. CLI core        — the hand-written application source (the entrypoint)
 *
 * Part 2 is mechanical: it must always equal what `src/` produces. This script
 * regenerates ONLY that section, between two markers, leaving the preamble and
 * the CLI core byte-identical. The committed bundle is therefore provably
 * reproducible from `src/` — `--check` fails on any drift. Re-using the same
 * `generateFactory` that `check-bundle.mjs` uses keeps the block format stable.
 *
 *   node scripts/build-bundle.mjs            # rewrite the bundled-modules section
 *   node scripts/build-bundle.mjs --check     # exit 1 if committed bundle != fresh build
 *
 * Zero dependencies. Wired into prepublishOnly + CI.
 */

import { readdirSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';
import { generateFactory } from './check-bundle.mjs';

const ROOT = fileURLToPath(new URL('..', import.meta.url));
const BUNDLE = join(ROOT, 'gen-context.js');

export const START_MARKER = '// ═══ SIGMAP BUNDLED MODULES — generated by scripts/build-bundle.mjs; do not edit by hand ═══';
export const END_MARKER = '// ═══ END SIGMAP BUNDLED MODULES ═══';

/** Recursively list .js files under a directory. */
function walk(dir) {
  const out = [];
  for (const e of readdirSync(dir, { withFileTypes: true })) {
    const full = join(dir, e.name);
    if (e.isDirectory()) out.push(...walk(full));
    else if (e.isFile() && e.name.endsWith('.js')) out.push(full);
  }
  return out;
}

/** Bundle key for a src file, e.g. "./src/tracking/logger". */
function keyFor(file, root) {
  return './' + file.slice(root.length).replace(/\.js$/, '').replace(/\\/g, '/').replace(/^\//, '');
}

/**
 * Directories whose `.js` modules are embedded in the bundle. The standalone
 * CLI loads these via `__require(...)` (no `src/` or `packages/` on disk), so
 * every module the CLI can reach at runtime must be here: all of `src/` plus
 * the adapter implementations.
 */
const BUNDLED_DIRS = ['src', join('packages', 'adapters')];

/**
 * Every embedded module key, sorted and de-duplicated — the canonical set.
 * @param {string} [root]
 * @returns {string[]}
 */
export function bundledModuleKeys(root = ROOT) {
  const keys = BUNDLED_DIRS.flatMap((d) => walk(join(root, d)).map((f) => keyFor(f, root)));
  return [...new Set(keys)].sort();
}

/** The full bundled-modules section (factory blocks joined). */
export function generateFactorySection(root = ROOT) {
  return bundledModuleKeys(root).map((k) => generateFactory(k)).join('\n\n');
}

/**
 * Assemble the canonical bundle: preamble + fresh factories + CLI core.
 * @param {string} [root]
 * @returns {string}
 */
export function buildBundle(root = ROOT) {
  const content = readFileSync(join(root, 'gen-context.js'), 'utf8');
  const s = content.indexOf(START_MARKER);
  const e = content.indexOf(END_MARKER);
  if (s === -1 || e === -1) {
    throw new Error('build-bundle: markers not found in gen-context.js — bootstrap them first');
  }
  const head = content.slice(0, s + START_MARKER.length);
  const tail = content.slice(e);
  return `${head}\n\n${generateFactorySection(root)}\n\n${tail}`;
}

/** Whether the committed bundle equals a fresh build. */
export function bundleInSync(root = ROOT) {
  return readFileSync(join(root, 'gen-context.js'), 'utf8') === buildBundle(root);
}

// ── CLI ──────────────────────────────────────────────────────────────────────
function main() {
  const check = process.argv.includes('--check');
  const count = bundledModuleKeys().length;
  if (check) {
    if (bundleInSync()) {
      console.log(`✓ gen-context.js is reproducible from src/ (${count} modules)`);
      return 0;
    }
    console.error('ERROR: gen-context.js differs from a fresh build of src/.');
    console.error('Run `npm run build:bundle` to regenerate it, then commit gen-context.js.');
    return 1;
  }
  writeFileSync(BUNDLE, buildBundle());
  console.log(`✓ rebuilt gen-context.js bundled-modules section (${count} modules)`);
  return 0;
}

if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
  process.exit(main());
}
