import { spawn } from "node:child_process";
import { createHash } from "node:crypto";
import {
  access,
  constants as fsConstants,
  copyFile,
  lstat,
  mkdir,
  mkdtemp,
  readFile,
  readdir,
  realpath,
  rename,
  rm,
  stat,
  writeFile,
} from "node:fs/promises";
import path from "node:path";
import { pathToFileURL } from "node:url";

export const PCRE2_LOCK = Object.freeze({
  bridgeAbi: 3,
  maximumPatternBytes: 1_048_576,
  maximumSubjectBytes: 16_777_216,
  maximumReplacementBytes: 262_144,
  maximumMatches: 10_000,
  maximumCaptureRows: 100_000,
  maximumCaptureGroups: 1_000,
  maximumTraceEvents: 50_000,
  maximumTraceBytes: 10_485_760,
  maximumTraceMarkBytes: 1_024,
  sourceDateEpoch: 1_760_997_684,
  source: Object.freeze({
    repository: "https://github.com/PCRE2Project/pcre2.git",
    tag: "pcre2-10.47",
    tagObject: "cd007b4466798f66d479d1442a407099e7c40050",
    commit: "f454e231fe5006dd7ff8f4693fd2b8eb94333429",
    tree: "81a83a3552bd68d0ea7b7004f8bb6e7892f583ba",
    version: "10.47 2025-10-21",
    license: "BSD-3-Clause WITH PCRE2-exception",
    criticalFiles: Object.freeze({
      "CMakeLists.txt":
        "74f65935e2b1120e7d7aeb4be81755e0f7a875732467ae64a9cc6ee7174fa5ba",
      "LICENCE.md":
        "197d8a73ffee0d6b09adba2f9c677b5f5aede24edf89258a68e48248d010d811",
      "src/pcre2.h.generic":
        "058462dc030e845ee627e19ac36347f561f5cc44d89eaf1c0010f2b363ab68d5",
    }),
  }),
  emscripten: Object.freeze({
    version: "6.0.4",
    compilerRevision: "fe5be6afdff43ad58860d821fcc8572a23f92d19",
    repositoryCommit: "224ec5f9f2f72f09f9ce0e26d66bae7dbd8b692f",
    emccSha256:
      "498eba9b6aacffca1c358ba340fc7b37015d7867cb211c7f2d45784ee9310f03",
    emcmakeSha256:
      "18c8397cf60835533e0db88d1172e04fa0b753dea68e978149d923a9e6378af3",
  }),
  cmakeVersion: "4.3.4",
  ninjaVersion: "1.13.2",
});

const PACK_FILES = Object.freeze([
  "LICENSE.txt",
  "SHA256SUMS",
  "engine-metadata.json",
  "pcre2.mjs",
  "pcre2.wasm",
]);
const CHECKSUM_FILES = Object.freeze([
  "LICENSE.txt",
  "engine-metadata.json",
  "pcre2.mjs",
  "pcre2.wasm",
]);
const BRIDGE_SOURCE_FILES = Object.freeze([
  "engines/pcre2/CMakeLists.txt",
  "engines/pcre2/pcre2_bridge.c",
  "engines/pcre2/pcre2_bridge.h",
]);
const EXPORTED_FUNCTIONS = Object.freeze([
  "_free",
  "_malloc",
  "_regex_pcre2_bridge_abi_version",
  "_regex_pcre2_compile_probe",
  "_regex_pcre2_config_flags",
  "_regex_pcre2_error_message",
  "_regex_pcre2_execute",
  "_regex_pcre2_self_test",
  "_regex_pcre2_substitute",
  "_regex_pcre2_trace",
  "_regex_pcre2_version",
]);

function sha256(data) {
  return createHash("sha256").update(data).digest("hex");
}

async function sha256File(file) {
  return sha256(await readFile(file));
}

function commandLabel(command, arguments_) {
  return [command, ...arguments_]
    .map((part) =>
      /^[A-Za-z0-9_./:=,+-]+$/u.test(part) ? part : JSON.stringify(part),
    )
    .join(" ");
}

async function run(command, arguments_, options = {}) {
  const child = spawn(command, arguments_, {
    cwd: options.cwd,
    env: options.env,
    stdio: ["ignore", "pipe", "pipe"],
  });
  const stdout = [];
  const stderr = [];
  child.stdout.on("data", (chunk) => stdout.push(chunk));
  child.stderr.on("data", (chunk) => stderr.push(chunk));

  const result = await new Promise((resolve, reject) => {
    child.once("error", reject);
    child.once("close", (code, signal) => resolve({ code, signal }));
  });
  const output = Buffer.concat(stdout).toString("utf8");
  const errorOutput = Buffer.concat(stderr).toString("utf8");
  if (result.code !== 0) {
    const detail = [output, errorOutput].filter(Boolean).join("\n").trim();
    throw new Error(
      `${commandLabel(command, arguments_)} failed with ${
        result.signal ? `signal ${result.signal}` : `exit code ${result.code}`
      }${detail ? `:\n${detail}` : "."}`,
    );
  }
  return { stdout: output, stderr: errorOutput };
}

async function assertRealDirectory(candidate, label) {
  const details = await lstat(candidate).catch(() => null);
  if (!details?.isDirectory() || details.isSymbolicLink()) {
    throw new Error(`${label} must be a real directory: ${candidate}`);
  }
  return realpath(candidate);
}

async function assertRegularFile(candidate, label) {
  const details = await lstat(candidate).catch(() => null);
  if (!details?.isFile() || details.isSymbolicLink()) {
    throw new Error(
      `${label} must be a regular, non-symlink file: ${candidate}`,
    );
  }
  return realpath(candidate);
}

async function assertHash(file, expected, label) {
  const actual = await sha256File(file);
  if (actual !== expected) {
    throw new Error(
      `${label} SHA-256 mismatch: expected ${expected}, got ${actual}.`,
    );
  }
}

async function resolveExecutable(name, environment = process.env) {
  const searchPath = environment.PATH ?? "";
  for (const directory of searchPath.split(path.delimiter)) {
    if (!directory) continue;
    const candidate = path.join(directory, name);
    try {
      await access(candidate, fsConstants.X_OK);
      const details = await stat(candidate);
      if (details.isFile()) return realpath(candidate);
    } catch {
      // Continue through PATH.
    }
  }
  throw new Error(`${name} is required on PATH for the explicit PCRE2 build.`);
}

function singleVersionLine(output) {
  return output.trim().split(/\r?\n/u)[0] ?? "";
}

async function verifyPcre2Source(sourceDirectory) {
  const source = await assertRealDirectory(sourceDirectory, "PCRE2 source");
  const git = await resolveExecutable("git");
  const status = await run(
    git,
    ["status", "--porcelain=v1", "--untracked-files=all"],
    { cwd: source },
  );
  if (status.stdout !== "") {
    throw new Error("The PCRE2 source checkout must be completely clean.");
  }

  const checks = [
    [["rev-parse", "HEAD"], PCRE2_LOCK.source.commit, "PCRE2 commit"],
    [["rev-parse", "HEAD^{tree}"], PCRE2_LOCK.source.tree, "PCRE2 source tree"],
    [
      ["rev-parse", `refs/tags/${PCRE2_LOCK.source.tag}^{tag}`],
      PCRE2_LOCK.source.tagObject,
      "PCRE2 signed tag object",
    ],
    [
      ["rev-parse", `refs/tags/${PCRE2_LOCK.source.tag}^{commit}`],
      PCRE2_LOCK.source.commit,
      "PCRE2 tag target",
    ],
  ];
  for (const [arguments_, expected, label] of checks) {
    const { stdout } = await run(git, arguments_, { cwd: source });
    const actual = stdout.trim();
    if (actual !== expected) {
      throw new Error(
        `${label} mismatch: expected ${expected}, got ${actual}.`,
      );
    }
  }

  for (const [relativePath, expected] of Object.entries(
    PCRE2_LOCK.source.criticalFiles,
  )) {
    await assertHash(
      path.join(source, relativePath),
      expected,
      `PCRE2 ${relativePath}`,
    );
  }
  return source;
}

async function verifyEmscripten(emccFile) {
  const emcc = await assertRegularFile(emccFile, "emcc");
  const emcmake = await assertRegularFile(
    path.join(path.dirname(emcc), "emcmake"),
    "emcmake",
  );
  await assertHash(emcc, PCRE2_LOCK.emscripten.emccSha256, "emcc");
  await assertHash(emcmake, PCRE2_LOCK.emscripten.emcmakeSha256, "emcmake");

  const version = await run(emcc, ["--version"]);
  const expectedVersion =
    `emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) ` +
    `${PCRE2_LOCK.emscripten.version} (${PCRE2_LOCK.emscripten.compilerRevision})`;
  if (singleVersionLine(version.stdout) !== expectedVersion) {
    throw new Error(
      `Emscripten identity mismatch: expected ${expectedVersion}, got ${singleVersionLine(
        version.stdout,
      )}.`,
    );
  }

  const git = await resolveExecutable("git");
  const repository = (
    await run(git, ["rev-parse", "--show-toplevel"], {
      cwd: path.dirname(emcc),
    })
  ).stdout.trim();
  const commit = (
    await run(git, ["rev-parse", "HEAD"], { cwd: repository })
  ).stdout.trim();
  if (commit !== PCRE2_LOCK.emscripten.repositoryCommit) {
    throw new Error(
      `Emscripten repository mismatch: expected ${PCRE2_LOCK.emscripten.repositoryCommit}, got ${commit}.`,
    );
  }
  const tagTarget = (
    await run(
      git,
      ["rev-parse", `refs/tags/${PCRE2_LOCK.emscripten.version}^{commit}`],
      {
        cwd: repository,
      },
    )
  ).stdout.trim();
  if (tagTarget !== PCRE2_LOCK.emscripten.repositoryCommit) {
    throw new Error(
      "The Emscripten 6.0.4 tag does not resolve to the pinned commit.",
    );
  }
  const status = await run(
    git,
    ["status", "--porcelain=v1", "--untracked-files=all"],
    { cwd: repository },
  );
  if (status.stdout !== "") {
    throw new Error("The Emscripten checkout must be completely clean.");
  }
  return { emcc, emcmake };
}

async function verifyNativeBuildTools() {
  const cmake = await resolveExecutable("cmake");
  const ninja = await resolveExecutable("ninja");
  const cmakeOutput = await run(cmake, ["--version"]);
  const ninjaOutput = await run(ninja, ["--version"]);
  if (
    singleVersionLine(cmakeOutput.stdout) !==
    `cmake version ${PCRE2_LOCK.cmakeVersion}`
  ) {
    throw new Error(
      `The PCRE2 pack requires CMake ${PCRE2_LOCK.cmakeVersion}.`,
    );
  }
  if (ninjaOutput.stdout.trim() !== PCRE2_LOCK.ninjaVersion) {
    throw new Error(
      `The PCRE2 pack requires Ninja ${PCRE2_LOCK.ninjaVersion}.`,
    );
  }
  return { cmake, ninja };
}

function parseValue(argv, index, option) {
  const value = argv[index + 1];
  if (!value || value.startsWith("--")) {
    throw new Error(`${option} requires a path.`);
  }
  return value;
}

export function parsePcre2BuildArguments(argv) {
  if (argv.length === 0) return { mode: "ecmascript" };
  if (argv.length === 1 && argv[0] === "--help") return { mode: "help" };

  let pcre2 = false;
  let sourceDirectory;
  let emccFile;
  let force = false;
  for (let index = 0; index < argv.length; index += 1) {
    const argument = argv[index];
    if (argument === "--pcre2") {
      if (pcre2) throw new Error("--pcre2 may be supplied only once.");
      pcre2 = true;
    } else if (argument === "--source-dir") {
      if (sourceDirectory)
        throw new Error("--source-dir may be supplied only once.");
      sourceDirectory = parseValue(argv, index, argument);
      index += 1;
    } else if (argument === "--emcc") {
      if (emccFile) throw new Error("--emcc may be supplied only once.");
      emccFile = parseValue(argv, index, argument);
      index += 1;
    } else if (argument === "--force") {
      if (force) throw new Error("--force may be supplied only once.");
      force = true;
    } else {
      throw new Error(`Unknown engine-build argument: ${argument}`);
    }
  }
  if (!pcre2) {
    throw new Error(
      "External engine options require the explicit --pcre2 gate.",
    );
  }
  if (!sourceDirectory || !emccFile) {
    throw new Error(
      "The offline PCRE2 build requires both --source-dir and --emcc; it never downloads them.",
    );
  }
  return { mode: "pcre2", sourceDirectory, emccFile, force };
}

async function bridgeSourceFiles(root) {
  return Promise.all(
    BRIDGE_SOURCE_FILES.map(async (relativePath) => {
      const contents = await readFile(path.join(root, relativePath));
      return {
        path: relativePath,
        sha256: sha256(contents),
        bytes: contents.byteLength,
      };
    }),
  );
}

async function describedFile(directory, name) {
  const contents = await readFile(path.join(directory, name));
  return { path: name, sha256: sha256(contents), bytes: contents.byteLength };
}

async function expectedMetadata(root, packDirectory) {
  const files = await Promise.all(
    ["LICENSE.txt", "pcre2.mjs", "pcre2.wasm"].map((name) =>
      describedFile(packDirectory, name),
    ),
  );
  return {
    schemaVersion: 1,
    engine: "pcre2",
    engineVersion: PCRE2_LOCK.source.version,
    status: "production-runtime",
    bridge: {
      abiVersion: PCRE2_LOCK.bridgeAbi,
      maximumPatternBytes: PCRE2_LOCK.maximumPatternBytes,
      maximumSubjectBytes: PCRE2_LOCK.maximumSubjectBytes,
      maximumReplacementBytes: PCRE2_LOCK.maximumReplacementBytes,
      maximumMatches: PCRE2_LOCK.maximumMatches,
      maximumCaptureRows: PCRE2_LOCK.maximumCaptureRows,
      maximumCaptureGroups: PCRE2_LOCK.maximumCaptureGroups,
      maximumTraceEvents: PCRE2_LOCK.maximumTraceEvents,
      maximumTraceBytes: PCRE2_LOCK.maximumTraceBytes,
      maximumTraceMarkBytes: PCRE2_LOCK.maximumTraceMarkBytes,
      sourceFiles: await bridgeSourceFiles(root),
      exports: [...EXPORTED_FUNCTIONS],
    },
    source: {
      repository: PCRE2_LOCK.source.repository,
      tag: PCRE2_LOCK.source.tag,
      tagObjectSha1: PCRE2_LOCK.source.tagObject,
      commitSha1: PCRE2_LOCK.source.commit,
      treeSha1: PCRE2_LOCK.source.tree,
      license: PCRE2_LOCK.source.license,
    },
    toolchain: {
      emscriptenVersion: PCRE2_LOCK.emscripten.version,
      emscriptenCompilerRevision: PCRE2_LOCK.emscripten.compilerRevision,
      emsdkCommitSha1: PCRE2_LOCK.emscripten.repositoryCommit,
      cmakeVersion: PCRE2_LOCK.cmakeVersion,
      ninjaVersion: PCRE2_LOCK.ninjaVersion,
    },
    configuration: {
      codeUnitWidth: 8,
      unicode: true,
      jit: false,
      threads: false,
      filesystem: false,
      initialMemoryBytes: 16_777_216,
      maximumMemoryBytes: 268_435_456,
    },
    sourceDateEpoch: PCRE2_LOCK.sourceDateEpoch,
    files,
  };
}

function deterministicJson(value) {
  return `${JSON.stringify(value, null, 2)}\n`;
}

async function expectedChecksums(packDirectory) {
  const entries = await Promise.all(
    CHECKSUM_FILES.map(
      async (name) =>
        `${await sha256File(path.join(packDirectory, name))}  ${name}`,
    ),
  );
  return `${entries.join("\n")}\n`;
}

function equalJson(left, right) {
  return JSON.stringify(left) === JSON.stringify(right);
}

async function smokePcre2Pack(packDirectory) {
  const wasm = await readFile(path.join(packDirectory, "pcre2.wasm"));
  if (
    wasm.byteLength < 8 ||
    !wasm.subarray(0, 4).equals(Buffer.from([0x00, 0x61, 0x73, 0x6d])) ||
    !WebAssembly.validate(wasm)
  ) {
    throw new Error("pcre2.wasm is not a valid WebAssembly module.");
  }

  const moduleUrl = `${pathToFileURL(path.join(packDirectory, "pcre2.mjs")).href}?sha256=${sha256(
    await readFile(path.join(packDirectory, "pcre2.mjs")),
  )}`;
  const imported = await import(moduleUrl);
  if (typeof imported.default !== "function") {
    throw new Error("pcre2.mjs does not export its Emscripten factory.");
  }
  const diagnostics = [];
  const module = await imported.default({
    locateFile(name) {
      return path.join(packDirectory, name);
    },
    print() {},
    printErr(line) {
      diagnostics.push(String(line));
    },
  });

  if (module._regex_pcre2_bridge_abi_version() !== PCRE2_LOCK.bridgeAbi) {
    throw new Error("The WebAssembly bridge ABI version is incorrect.");
  }
  if (module._regex_pcre2_config_flags() !== 1) {
    throw new Error(
      "The WebAssembly pack must have Unicode enabled and JIT disabled.",
    );
  }
  if (
    module.UTF8ToString(module._regex_pcre2_version()) !==
    PCRE2_LOCK.source.version
  ) {
    throw new Error("The WebAssembly PCRE2 version is incorrect.");
  }
  if (module._regex_pcre2_self_test() !== 0) {
    throw new Error(
      `The WebAssembly bridge self-test failed: ${diagnostics.join("\n")}`,
    );
  }

  const pattern = new TextEncoder().encode("(?<word>\\p{L}+)-(?<number>\\d+)");
  const patternPointer = module._malloc(pattern.byteLength);
  const resultPointer = module._malloc(20);
  if (!patternPointer || !resultPointer) {
    if (patternPointer) module._free(patternPointer);
    if (resultPointer) module._free(resultPointer);
    throw new Error("The WebAssembly smoke test could not allocate memory.");
  }
  try {
    module.HEAPU8.set(pattern, patternPointer);
    module.HEAPU8.fill(0, resultPointer, resultPointer + 20);
    const status = module._regex_pcre2_compile_probe(
      patternPointer,
      pattern.byteLength,
      0x20 | 0x40,
      resultPointer,
    );
    const result = new DataView(module.HEAPU8.buffer, resultPointer, 20);
    if (
      status !== 0 ||
      result.getInt32(0, true) !== 0 ||
      result.getUint32(8, true) !== 2 ||
      result.getUint32(12, true) !== 2
    ) {
      throw new Error("The WebAssembly compile-probe result is incorrect.");
    }

    module.HEAPU8.fill(0, resultPointer, resultPointer + 20);
    const unsupportedStatus = module._regex_pcre2_compile_probe(
      patternPointer,
      pattern.byteLength,
      0x80000000,
      resultPointer,
    );
    if (unsupportedStatus !== -10002 || result.getInt32(0, true) !== -10002) {
      throw new Error("The WebAssembly bridge accepted an unknown option bit.");
    }

    module.HEAPU8[patternPointer] = 0x28;
    module.HEAPU8.fill(0, resultPointer, resultPointer + 20);
    const invalidStatus = module._regex_pcre2_compile_probe(
      patternPointer,
      1,
      0,
      resultPointer,
    );
    if (
      invalidStatus <= 0 ||
      result.getInt32(0, true) !== invalidStatus ||
      result.getUint32(4, true) > 1
    ) {
      throw new Error(
        "The WebAssembly bridge did not preserve the compile error.",
      );
    }

    if (
      module._regex_pcre2_compile_probe(0, 1, 0, resultPointer) !== -10001 ||
      module._regex_pcre2_compile_probe(
        patternPointer,
        PCRE2_LOCK.maximumPatternBytes + 1,
        0,
        resultPointer,
      ) !== -10003
    ) {
      throw new Error("The WebAssembly bridge input limits are not enforced.");
    }
  } finally {
    module._free(resultPointer);
    module._free(patternPointer);
  }

  const runPattern = new TextEncoder().encode("(?<emoji>😀)|(?<word>\\p{L}+)");
  const runSubject = new TextEncoder().encode("x😀 Grüße");
  const runPointers = [];
  const allocate = (bytes) => {
    const pointer = module._malloc(Math.max(1, bytes));
    if (!pointer) throw new Error("The PCRE2 runtime smoke allocation failed.");
    runPointers.push(pointer);
    return pointer;
  };
  try {
    const runPatternPointer = allocate(runPattern.byteLength);
    const runSubjectPointer = allocate(runSubject.byteLength);
    const limitsPointer = allocate(20);
    const recordsPointer = allocate(20 * 16);
    const namesPointer = allocate(10 * 12);
    const nameBytesPointer = allocate(256);
    const runResultPointer = allocate(60);
    module.HEAPU8.set(runPattern, runPatternPointer);
    module.HEAPU8.set(runSubject, runSubjectPointer);
    let view = new DataView(module.HEAPU8.buffer);
    view.setUint32(limitsPointer, 10, true);
    view.setUint32(limitsPointer + 4, 100, true);
    view.setUint32(limitsPointer + 8, 1_000_000, true);
    view.setUint32(limitsPointer + 12, 1_000, true);
    view.setUint32(limitsPointer + 16, 32_768, true);
    module.HEAPU8.fill(0, runResultPointer, runResultPointer + 60);
    const runStatus = module._regex_pcre2_execute(
      runPatternPointer,
      runPattern.byteLength,
      runSubjectPointer,
      runSubject.byteLength,
      0x20 | 0x40 | 0x100,
      limitsPointer,
      recordsPointer,
      20,
      namesPointer,
      10,
      nameBytesPointer,
      256,
      runResultPointer,
    );
    view = new DataView(module.HEAPU8.buffer);
    if (
      runStatus !== 0 ||
      view.getInt32(runResultPointer, true) !== 0 ||
      view.getUint32(runResultPointer + 12, true) !== 2 ||
      view.getUint32(runResultPointer + 20, true) !== 3 ||
      view.getUint32(runResultPointer + 24, true) !== 9 ||
      view.getUint32(recordsPointer + 3 * 16 + 8, true) !== 1 ||
      view.getUint32(recordsPointer + 3 * 16 + 12, true) !== 5
    ) {
      throw new Error("The WebAssembly bounded-match smoke result is wrong.");
    }

    const replacementPattern = new TextEncoder().encode("(?<word>\\p{L}+)");
    const replacementSubject = new TextEncoder().encode("Grüße 42");
    const replacement = new TextEncoder().encode("${word}!");
    const replacementPatternPointer = allocate(replacementPattern.byteLength);
    const replacementSubjectPointer = allocate(replacementSubject.byteLength);
    const replacementPointer = allocate(replacement.byteLength);
    const outputPointer = allocate(65);
    module.HEAPU8.set(replacementPattern, replacementPatternPointer);
    module.HEAPU8.set(replacementSubject, replacementSubjectPointer);
    module.HEAPU8.set(replacement, replacementPointer);
    module.HEAPU8.fill(0, runResultPointer, runResultPointer + 60);
    const substituteStatus = module._regex_pcre2_substitute(
      replacementPatternPointer,
      replacementPattern.byteLength,
      replacementSubjectPointer,
      replacementSubject.byteLength,
      replacementPointer,
      replacement.byteLength,
      0x20 | 0x40 | 0x100,
      limitsPointer,
      recordsPointer,
      20,
      namesPointer,
      10,
      nameBytesPointer,
      256,
      outputPointer,
      64,
      runResultPointer,
    );
    view = new DataView(module.HEAPU8.buffer);
    const outputLength = view.getUint32(runResultPointer + 48, true);
    const output = new TextDecoder().decode(
      module.HEAPU8.slice(outputPointer, outputPointer + outputLength),
    );
    if (
      substituteStatus !== 0 ||
      output !== "Grüße! 42" ||
      view.getUint32(runResultPointer + 52, true) !== 1 ||
      view.getUint32(runResultPointer + 56, true) !== 0
    ) {
      throw new Error(
        "The WebAssembly bounded-substitution smoke result is wrong.",
      );
    }
    module.HEAPU8.fill(0, runResultPointer, runResultPointer + 60);
    const missingOutputStatus = module._regex_pcre2_substitute(
      replacementPatternPointer,
      replacementPattern.byteLength,
      replacementSubjectPointer,
      replacementSubject.byteLength,
      replacementPointer,
      replacement.byteLength,
      0x20 | 0x40,
      limitsPointer,
      recordsPointer,
      20,
      namesPointer,
      10,
      nameBytesPointer,
      256,
      0,
      0,
      runResultPointer,
    );
    if (
      missingOutputStatus !== -10001 ||
      view.getInt32(runResultPointer, true) !== -10001
    ) {
      throw new Error(
        "The WebAssembly substitution bridge accepted a missing NUL byte.",
      );
    }

    const traceEventsPointer = allocate(64 * 32);
    const traceMarksPointer = allocate(256);
    const traceResultPointer = allocate(52);
    view.setUint32(limitsPointer, 64, true);
    view.setUint32(limitsPointer + 4, 4_096, true);
    module.HEAPU8.fill(0, traceResultPointer, traceResultPointer + 52);
    const traceStatus = module._regex_pcre2_trace(
      runPatternPointer,
      runPattern.byteLength,
      runSubjectPointer,
      runSubject.byteLength,
      0x20 | 0x40,
      limitsPointer,
      traceEventsPointer,
      64,
      traceMarksPointer,
      256,
      traceResultPointer,
    );
    view = new DataView(module.HEAPU8.buffer);
    const traceEventCount = view.getUint32(traceResultPointer + 20, true);
    if (
      traceStatus !== 0 ||
      view.getInt32(traceResultPointer, true) !== 0 ||
      view.getInt32(traceResultPointer + 12, true) <= 0 ||
      traceEventCount === 0 ||
      view.getUint32(traceResultPointer + 24, true) !== traceEventCount ||
      view.getUint32(traceResultPointer + 36, true) !== 0 ||
      view.getUint32(traceResultPointer + 44, true) !== traceEventCount - 1 ||
      view.getUint32(traceResultPointer + 48, true) !== 1
    ) {
      throw new Error("The WebAssembly automatic-callout trace is wrong.");
    }

    view.setUint32(limitsPointer, 1, true);
    module.HEAPU8.fill(0, traceResultPointer, traceResultPointer + 52);
    const boundedTraceStatus = module._regex_pcre2_trace(
      runPatternPointer,
      runPattern.byteLength,
      runSubjectPointer,
      runSubject.byteLength,
      0x20 | 0x40,
      limitsPointer,
      traceEventsPointer,
      64,
      traceMarksPointer,
      256,
      traceResultPointer,
    );
    if (
      boundedTraceStatus !== 0 ||
      view.getInt32(traceResultPointer, true) !== 0 ||
      view.getInt32(traceResultPointer + 12, true) !== -37 ||
      view.getUint32(traceResultPointer + 20, true) !== 1 ||
      view.getUint32(traceResultPointer + 24, true) !== 2 ||
      view.getUint32(traceResultPointer + 36, true) !== 1 ||
      view.getUint32(traceResultPointer + 44, true) !== 0
    ) {
      throw new Error("The WebAssembly trace cap is not authoritative.");
    }
  } finally {
    for (const pointer of runPointers.reverse()) module._free(pointer);
  }
}

export async function verifyPcre2Pack(packDirectory, root) {
  const repositoryRoot = await assertRealDirectory(
    root,
    "Regex Tools repository",
  );
  const pack = await assertRealDirectory(packDirectory, "PCRE2 pack");
  const entries = (await readdir(pack, { withFileTypes: true })).sort(
    (left, right) =>
      left.name < right.name ? -1 : left.name > right.name ? 1 : 0,
  );
  if (
    entries.length !== PACK_FILES.length ||
    entries.some(
      (entry, index) =>
        entry.name !== PACK_FILES[index] ||
        !entry.isFile() ||
        entry.isSymbolicLink(),
    )
  ) {
    throw new Error(
      `The staged PCRE2 pack must contain only: ${PACK_FILES.join(", ")}.`,
    );
  }

  await assertHash(
    path.join(pack, "LICENSE.txt"),
    PCRE2_LOCK.source.criticalFiles["LICENCE.md"],
    "staged PCRE2 licence",
  );
  const moduleText = await readFile(path.join(pack, "pcre2.mjs"), "utf8");
  if (
    moduleText.includes("sourceMappingURL") ||
    moduleText.includes("/mnt/") ||
    moduleText.includes("/home/")
  ) {
    throw new Error("pcre2.mjs leaks a build path or source-map reference.");
  }

  let metadata;
  try {
    metadata = JSON.parse(
      await readFile(path.join(pack, "engine-metadata.json"), "utf8"),
    );
  } catch (error) {
    throw new Error("engine-metadata.json is not valid JSON.", {
      cause: error,
    });
  }
  const expected = await expectedMetadata(repositoryRoot, pack);
  if (!equalJson(metadata, expected)) {
    throw new Error(
      "The staged PCRE2 metadata does not match the pinned build contract.",
    );
  }
  const checksums = await readFile(path.join(pack, "SHA256SUMS"), "utf8");
  if (checksums !== (await expectedChecksums(pack))) {
    throw new Error("The staged PCRE2 SHA256SUMS file is incorrect.");
  }
  await smokePcre2Pack(pack);
  return metadata;
}

export async function installPcre2Pack(packDirectory, root) {
  const repositoryRoot = await assertRealDirectory(
    root,
    "Regex Tools repository",
  );
  const sourcePack = await assertRealDirectory(
    packDirectory,
    "verified PCRE2 pack",
  );
  const metadata = await verifyPcre2Pack(sourcePack, repositoryRoot);
  const engineRoot = await assertRealDirectory(
    path.join(repositoryRoot, "public", "engines"),
    "public engine directory",
  );
  const target = path.join(engineRoot, "pcre2");
  const stage = await mkdtemp(path.join(engineRoot, ".pcre2-install-"));
  const targetDetails = await lstat(target).catch(() => null);
  if (
    targetDetails &&
    (!targetDetails.isDirectory() || targetDetails.isSymbolicLink())
  ) {
    await rm(stage, { recursive: true, force: true });
    throw new Error("public/engines/pcre2 must be a real directory.");
  }
  try {
    for (const name of PACK_FILES) {
      await copyFile(
        path.join(sourcePack, name),
        path.join(stage, name),
        fsConstants.COPYFILE_EXCL,
      );
    }
    await verifyPcre2Pack(stage, repositoryRoot);
    if (targetDetails) {
      const backup = path.join(engineRoot, `.pcre2-replaced-${process.pid}`);
      await rename(target, backup);
      try {
        await rename(stage, target);
      } catch (error) {
        await rename(backup, target);
        throw error;
      }
      await rm(backup, { recursive: true });
    } else {
      await rename(stage, target);
    }
    return { output: target, metadata };
  } finally {
    await rm(stage, { recursive: true, force: true });
  }
}

function cleanBuildEnvironment() {
  const environment = { ...process.env };
  for (const variable of [
    "CFLAGS",
    "CPPFLAGS",
    "CXXFLAGS",
    "DESTDIR",
    "EMCC_CFLAGS",
    "EMMAKEN_CFLAGS",
    "LDFLAGS",
  ]) {
    delete environment[variable];
  }
  environment.LANG = "C";
  environment.LC_ALL = "C";
  environment.SOURCE_DATE_EPOCH = String(PCRE2_LOCK.sourceDateEpoch);
  environment.TZ = "UTC";
  environment.ZERO_AR_DATE = "1";
  return environment;
}

async function ensurePrivateBuildRoot(root) {
  const buildRoot = path.join(root, ".engine-build");
  const existing = await lstat(buildRoot).catch(() => null);
  if (existing && (!existing.isDirectory() || existing.isSymbolicLink())) {
    throw new Error(".engine-build must be a real directory.");
  }
  await mkdir(buildRoot, { recursive: true });
  return realpath(buildRoot);
}

function assertGeneratedChild(buildRoot, candidate) {
  const relative = path.relative(buildRoot, candidate);
  if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
    throw new Error(
      `Refusing to remove a path outside .engine-build: ${candidate}`,
    );
  }
}

export async function buildPcre2Pack(options, root) {
  const repositoryRoot = await assertRealDirectory(
    root,
    "Regex Tools repository",
  );
  const source = await verifyPcre2Source(options.sourceDirectory);
  const { emcmake } = await verifyEmscripten(options.emccFile);
  const { cmake, ninja } = await verifyNativeBuildTools();
  const buildRoot = await ensurePrivateBuildRoot(repositoryRoot);
  const output = path.join(buildRoot, "pcre2");
  const outputDetails = await lstat(output).catch(() => null);
  if (outputDetails && !options.force) {
    throw new Error(
      `${output} already exists; pass --force to replace that exact staged pack.`,
    );
  }

  const work = await mkdtemp(path.join(buildRoot, ".pcre2-work-"));
  const stage = await mkdtemp(path.join(buildRoot, ".pcre2-stage-"));
  assertGeneratedChild(buildRoot, work);
  assertGeneratedChild(buildRoot, stage);
  const environment = cleanBuildEnvironment();
  try {
    await run(
      emcmake,
      [
        cmake,
        "-S",
        path.join(repositoryRoot, "engines", "pcre2"),
        "-B",
        work,
        "-G",
        "Ninja",
        "-DCMAKE_BUILD_TYPE=Release",
        `-DCMAKE_MAKE_PROGRAM=${ninja}`,
        `-DPCRE2_SOURCE_DIR=${source}`,
        `-DREGEX_PCRE2_OUTPUT_DIR=${stage}`,
      ],
      { cwd: repositoryRoot, env: environment },
    );
    await run(
      cmake,
      ["--build", work, "--target", "regex-pcre2-pack", "--parallel", "1"],
      {
        cwd: repositoryRoot,
        env: environment,
      },
    );

    const generatedEntries = (await readdir(stage)).sort();
    if (
      generatedEntries.length !== 2 ||
      generatedEntries[0] !== "pcre2.mjs" ||
      generatedEntries[1] !== "pcre2.wasm"
    ) {
      throw new Error(
        `Emscripten produced unexpected files: ${generatedEntries.join(", ") || "(none)"}.`,
      );
    }
    await copyFile(
      path.join(source, "LICENCE.md"),
      path.join(stage, "LICENSE.txt"),
      fsConstants.COPYFILE_EXCL,
    );
    const metadata = await expectedMetadata(repositoryRoot, stage);
    await writeFile(
      path.join(stage, "engine-metadata.json"),
      deterministicJson(metadata),
      { encoding: "utf8", flag: "wx" },
    );
    await writeFile(
      path.join(stage, "SHA256SUMS"),
      await expectedChecksums(stage),
      { encoding: "utf8", flag: "wx" },
    );
    await verifyPcre2Pack(stage, repositoryRoot);

    if (outputDetails) {
      const backup = path.join(buildRoot, `.pcre2-replaced-${process.pid}`);
      assertGeneratedChild(buildRoot, backup);
      await rename(output, backup);
      try {
        await rename(stage, output);
      } catch (error) {
        await rename(backup, output);
        throw error;
      }
      await rm(backup, { recursive: true });
    } else {
      await rename(stage, output);
    }
    return { output, metadata };
  } finally {
    await rm(work, { recursive: true, force: true });
    await rm(stage, { recursive: true, force: true });
  }
}
