import type { RegexEngineAdapter } from "../../RegexEngineAdapter";
import {
  buildUtf8OffsetMap,
  utf8ByteToUtf16,
  type Utf8OffsetMap,
} from "../../offsets/utf8-to-utf16";
import { DEFAULT_REGEX_LIMITS } from "../../request-limits";
import type { RegexDiagnostic } from "../../../model/diagnostics";
import type {
  RegexEngineInfo,
  RegexEngineOptions,
} from "../../../model/flavour";
import type {
  CaptureResult,
  RegexExecutionFlags,
  RegexExecutionRequest,
  RegexExecutionResult,
  RegexMatchResult,
  RegexReplacementRequest,
  RegexReplacementResult,
} from "../../../model/match";
import type { Pcre2EmscriptenModule } from "./pcre2-module";
import { APPLICATION_VERSION } from "../../../../version";

export const PCRE2_ADAPTER_VERSION = APPLICATION_VERSION;
export const PCRE2_ENGINE_VERSION = "10.47 2025-10-21";
export const PCRE2_FLAVOUR_VERSION = "PCRE2 10.47 8-bit WebAssembly";
const PCRE2_COMPATIBLE_FLAVOUR_VERSIONS = new Set([
  PCRE2_FLAVOUR_VERSION,
  "PCRE2 10.47",
  "10.47",
]);
export const PCRE2_BRIDGE_ABI_VERSION = 3;

const TEXT_ENCODER = new TextEncoder();
const TEXT_DECODER = new TextDecoder("utf-8", { fatal: true });
const RESULT_BYTES = 60;
const LIMIT_BYTES = 20;
const MATCH_RECORD_BYTES = 16;
const NAME_RECORD_BYTES = 12;
const NAME_BYTES_CAPACITY = 64 * 1024;
const ERROR_MESSAGE_BYTES = 256;
const UNSET_OFFSET = 0xffff_ffff;
const CAPTURE_VALUE_PREVIEW_UTF16 = 64 * 1024;
const TOTAL_VALUE_PREVIEW_UTF16 = 8 * 1024 * 1024;

const FLAG_BITS = {
  i: 1 << 0,
  m: 1 << 1,
  s: 1 << 2,
  x: 1 << 3,
  U: 1 << 4,
  J: 1 << 7,
  g: 1 << 8,
} as const;
const FLAG_ORDER = "gimsxUJ";
const UTF_AND_UCP_BITS = (1 << 5) | (1 << 6);

interface Pcre2Limits {
  readonly matchLimit: number;
  readonly depthLimit: number;
  readonly heapLimitKib: number;
}

interface NativeRunResult {
  readonly status: number;
  readonly errorPhase: number;
  readonly errorOffset: number;
  readonly captureCount: number;
  readonly nameCount: number;
  readonly matchCount: number;
  readonly recordCount: number;
  readonly nameRecordCount: number;
  readonly nameBytesLength: number;
  readonly effectiveOptions: number;
  readonly resultsTruncated: boolean;
  readonly namesTruncated: boolean;
  readonly outputLength: number;
  readonly substitutionCount: number;
  readonly outputTruncated: boolean;
}

interface NativeBuffers {
  readonly recordsPointer: number;
  readonly namesPointer: number;
  readonly nameBytesPointer: number;
  readonly outputPointer: number;
  readonly resultPointer: number;
  readonly recordCapacity: number;
}

class WasmAllocations {
  readonly #module: Pcre2EmscriptenModule;
  readonly #pointers: number[] = [];

  constructor(module: Pcre2EmscriptenModule) {
    this.#module = module;
  }

  allocate(bytes: number): number {
    const pointer = this.#module._malloc(Math.max(1, bytes));
    if (!pointer) {
      throw new Error(
        `PCRE2 WebAssembly could not allocate ${bytes.toLocaleString()} bytes.`,
      );
    }
    this.#pointers.push(pointer);
    return pointer;
  }

  encoded(value: Uint8Array): number {
    const pointer = this.allocate(value.byteLength);
    if (value.byteLength > 0) {
      this.#module.HEAPU8.set(value, pointer);
    }
    return pointer;
  }

  free(): void {
    for (let index = this.#pointers.length - 1; index >= 0; index -= 1) {
      this.#module._free(this.#pointers[index] ?? 0);
    }
    this.#pointers.length = 0;
  }
}

class ValuePreviewBudget {
  #remaining = TOTAL_VALUE_PREVIEW_UTF16;
  truncated = false;

  take(value: string): { readonly value: string; readonly truncated: boolean } {
    const maximum = Math.min(CAPTURE_VALUE_PREVIEW_UTF16, this.#remaining);
    const preview = value.slice(0, maximum);
    this.#remaining -= preview.length;
    const truncated = preview.length !== value.length;
    this.truncated ||= truncated;
    return { value: preview, truncated };
  }
}

export function pcre2EngineInfo(runtimeVersion?: string): RegexEngineInfo {
  return {
    flavour: "pcre2",
    adapterVersion: PCRE2_ADAPTER_VERSION,
    engineName: "PCRE2 WebAssembly",
    engineVersion: PCRE2_ENGINE_VERSION,
    ...(runtimeVersion ? { runtimeVersion } : {}),
    offsetUnit: "utf8-byte",
    capabilities: {
      compilation: true,
      matching: true,
      replacement: true,
      namedCaptures: true,
      captureHistory: false,
      actualTrace: true,
      benchmark: false,
    },
  };
}

function integerOption(
  options: RegexEngineOptions | undefined,
  name: string,
  fallback: number,
  minimum: number,
  maximum: number,
): number {
  const value = options?.[name] ?? fallback;
  if (
    typeof value !== "number" ||
    !Number.isSafeInteger(value) ||
    value < minimum ||
    value > maximum
  ) {
    throw new RangeError(
      `PCRE2 option ${name} must be an integer from ${minimum.toLocaleString()} to ${maximum.toLocaleString()}.`,
    );
  }
  return value;
}

export function pcre2Limits(options?: RegexEngineOptions): Pcre2Limits {
  return {
    matchLimit: integerOption(options, "matchLimit", 1_000_000, 1, 100_000_000),
    depthLimit: integerOption(options, "depthLimit", 1_000, 1, 100_000),
    heapLimitKib: integerOption(options, "heapLimitKib", 32_768, 1, 131_072),
  };
}

export function normalizedPcre2Flags(
  userFlags: readonly string[],
  scanAll: boolean,
): RegexExecutionFlags {
  const selected = new Set(userFlags);
  const internallyAddedGlobalFlag = scanAll && !selected.has("g");
  if (internallyAddedGlobalFlag) selected.add("g");
  return {
    userFlags: [...FLAG_ORDER]
      .filter((flag) => userFlags.includes(flag))
      .join(""),
    effectiveFlags: [...FLAG_ORDER]
      .filter((flag) => selected.has(flag))
      .join(""),
    internallyAddedIndicesFlag: false,
    internallyAddedGlobalFlag,
  };
}

export function pcre2ApplicationFlags(flags: RegexExecutionFlags): number {
  let result = UTF_AND_UCP_BITS;
  for (const flag of flags.effectiveFlags) {
    result |= FLAG_BITS[flag as keyof typeof FLAG_BITS] ?? 0;
  }
  return result;
}

function validateRequestBounds(
  request: RegexExecutionRequest,
  patternBytes: number,
  subjectBytes: number,
  replacement?: {
    readonly bytes: number;
    readonly maximumOutputBytes: number;
  },
): void {
  if (
    new Set(request.flags).size !== request.flags.length ||
    request.flags.some(
      (flag) => flag.length !== 1 || !FLAG_ORDER.includes(flag),
    )
  ) {
    throw new RangeError("The request contains unsupported PCRE2 flags.");
  }
  const supportedOptions = new Set([
    "matchLimit",
    "depthLimit",
    "heapLimitKib",
  ]);
  if (
    request.options &&
    Object.keys(request.options).some((name) => !supportedOptions.has(name))
  ) {
    throw new RangeError(
      "The request contains unsupported PCRE2 engine options.",
    );
  }
  if (patternBytes > 1_048_576) {
    throw new RangeError("PCRE2 patterns are limited to 1 MiB of UTF-8.");
  }
  if (subjectBytes > DEFAULT_REGEX_LIMITS.interactiveSubjectHardBytes) {
    throw new RangeError("PCRE2 subjects are limited to 16 MiB of UTF-8.");
  }
  if (
    !Number.isSafeInteger(request.maximumMatches) ||
    request.maximumMatches < 1 ||
    request.maximumMatches > DEFAULT_REGEX_LIMITS.maximumMatches ||
    !Number.isSafeInteger(request.maximumCaptureRows) ||
    request.maximumCaptureRows < 1 ||
    request.maximumCaptureRows > DEFAULT_REGEX_LIMITS.maximumCaptureRows
  ) {
    throw new RangeError(
      "PCRE2 result limits are outside the bounded contract.",
    );
  }
  if (
    replacement &&
    (replacement.bytes > 262_144 ||
      !Number.isSafeInteger(replacement.maximumOutputBytes) ||
      replacement.maximumOutputBytes < 1 ||
      replacement.maximumOutputBytes >
        DEFAULT_REGEX_LIMITS.maximumReplacementOutputBytes)
  ) {
    throw new RangeError(
      "PCRE2 replacement or output limits are outside the bounded contract.",
    );
  }
}

function validateNativeBounds(
  native: NativeRunResult,
  buffers: NativeBuffers,
  maximumOutputBytes?: number,
): void {
  if (
    native.captureCount > DEFAULT_REGEX_LIMITS.maximumCaptureGroups ||
    native.matchCount > DEFAULT_REGEX_LIMITS.maximumMatches ||
    native.recordCount > buffers.recordCapacity ||
    native.nameRecordCount > DEFAULT_REGEX_LIMITS.maximumCaptureGroups ||
    native.nameBytesLength > NAME_BYTES_CAPACITY ||
    (maximumOutputBytes !== undefined &&
      native.outputLength > maximumOutputBytes)
  ) {
    throw new Error("PCRE2 returned data outside the bounded bridge contract.");
  }
}

function bridgeMessage(status: number): string | undefined {
  switch (status) {
    case -10_001:
      return "The PCRE2 bridge received an invalid argument.";
    case -10_002:
      return "The request contains unsupported PCRE2 flags.";
    case -10_003:
      return "The pattern exceeds the PCRE2 bridge byte limit.";
    case -10_004:
      return "The PCRE2 runtime configuration is inconsistent.";
    case -10_005:
      return "The subject exceeds the PCRE2 bridge byte limit.";
    case -10_006:
      return "The replacement exceeds the PCRE2 bridge byte limit.";
    case -10_007:
      return "A PCRE2 resource limit is outside its supported range.";
    case -10_008:
      return "The pattern exceeds the 1,000 capture-group execution limit.";
    case -10_009:
      return "The PCRE2 output buffer is invalid.";
    default:
      return undefined;
  }
}

function containsLoneSurrogate(
  value: string,
  label: string,
): RegexDiagnostic | undefined {
  const map = buildUtf8OffsetMap(value);
  if (!map.containsLoneSurrogate) return undefined;
  return {
    id: `pcre2-${label}-lone-surrogate`,
    source: "execution-engine",
    severity: "error",
    code: "invalid-unicode-input",
    message: `${label} contains an unpaired UTF-16 surrogate. PCRE2 UTF-8 execution refuses the lossy browser encoding that would otherwise replace it.`,
    flavour: "pcre2",
    provenance: "derived",
  };
}

function runResult(
  module: Pcre2EmscriptenModule,
  pointer: number,
): NativeRunResult {
  const view = new DataView(module.HEAPU8.buffer, pointer, RESULT_BYTES);
  return {
    status: view.getInt32(0, true),
    errorPhase: view.getUint32(4, true),
    errorOffset: view.getUint32(8, true),
    captureCount: view.getUint32(12, true),
    nameCount: view.getUint32(16, true),
    matchCount: view.getUint32(20, true),
    recordCount: view.getUint32(24, true),
    nameRecordCount: view.getUint32(28, true),
    nameBytesLength: view.getUint32(32, true),
    effectiveOptions: view.getUint32(36, true),
    resultsTruncated: view.getUint32(40, true) !== 0,
    namesTruncated: view.getUint32(44, true) !== 0,
    outputLength: view.getUint32(48, true),
    substitutionCount: view.getUint32(52, true),
    outputTruncated: view.getUint32(56, true) !== 0,
  };
}

function nativeErrorMessage(
  module: Pcre2EmscriptenModule,
  status: number,
): string {
  const bridge = bridgeMessage(status);
  if (bridge) return bridge;
  const pointer = module._malloc(ERROR_MESSAGE_BYTES);
  if (!pointer) return `PCRE2 error ${status}`;
  try {
    module.HEAPU8.fill(0, pointer, pointer + ERROR_MESSAGE_BYTES);
    const length = module._regex_pcre2_error_message(
      status,
      pointer,
      ERROR_MESSAGE_BYTES,
    );
    return length >= 0
      ? TEXT_DECODER.decode(module.HEAPU8.slice(pointer, pointer + length))
      : `PCRE2 error ${status}`;
  } finally {
    module._free(pointer);
  }
}

function diagnosticForFailure(
  module: Pcre2EmscriptenModule,
  native: NativeRunResult,
  patternMap: Utf8OffsetMap,
): RegexDiagnostic {
  const phase =
    native.errorPhase === 2
      ? "compile"
      : native.errorPhase === 3
        ? "match"
        : native.errorPhase === 4
          ? "replacement"
          : "bridge";
  const nativeMessage = nativeErrorMessage(module, native.status);
  let range:
    { readonly startUtf16: number; readonly endUtf16: number } | undefined;
  if (native.errorPhase === 2) {
    try {
      const offset = utf8ByteToUtf16(patternMap, native.errorOffset);
      range = { startUtf16: offset, endUtf16: offset };
    } catch {
      range = undefined;
    }
  }
  return {
    id: `pcre2-${phase}-error`,
    source: "execution-engine",
    severity: "error",
    code:
      native.errorPhase === 2
        ? "compile-error"
        : native.errorPhase === 4
          ? "replacement-error"
          : native.status === -47
            ? "match-limit"
            : "execution-error",
    message: `PCRE2 ${phase} error: ${nativeMessage}`,
    ...(range ? { range } : {}),
    flavour: "pcre2",
    provenance: "reported",
  };
}

function writeLimits(
  module: Pcre2EmscriptenModule,
  pointer: number,
  request: RegexExecutionRequest,
  limits: Pcre2Limits,
): void {
  const view = new DataView(module.HEAPU8.buffer, pointer, LIMIT_BYTES);
  view.setUint32(0, request.maximumMatches, true);
  view.setUint32(4, request.maximumCaptureRows, true);
  view.setUint32(8, limits.matchLimit, true);
  view.setUint32(12, limits.depthLimit, true);
  view.setUint32(16, limits.heapLimitKib, true);
}

function namesByGroup(
  module: Pcre2EmscriptenModule,
  buffers: NativeBuffers,
  native: NativeRunResult,
  request: RegexExecutionRequest,
): ReadonlyMap<number, string> {
  const names = new Map(
    request.captureMetadata.flatMap((capture) =>
      capture.name ? [[capture.number, capture.name] as const] : [],
    ),
  );
  const view = new DataView(module.HEAPU8.buffer);
  for (let index = 0; index < native.nameRecordCount; index += 1) {
    const pointer = buffers.namesPointer + index * NAME_RECORD_BYTES;
    const groupNumber = view.getUint32(pointer, true);
    const offset = view.getUint32(pointer + 4, true);
    const length = view.getUint32(pointer + 8, true);
    if (offset + length > native.nameBytesLength) {
      throw new Error("PCRE2 returned an invalid capture-name range.");
    }
    names.set(
      groupNumber,
      TEXT_DECODER.decode(
        module.HEAPU8.slice(
          buffers.nameBytesPointer + offset,
          buffers.nameBytesPointer + offset + length,
        ),
      ),
    );
  }
  return names;
}

function materializeMatches(
  module: Pcre2EmscriptenModule,
  buffers: NativeBuffers,
  native: NativeRunResult,
  request: RegexExecutionRequest,
  subjectMap: Utf8OffsetMap,
): {
  readonly matches: readonly RegexMatchResult[];
  readonly valuesTruncated: boolean;
} {
  const names = namesByGroup(module, buffers, native, request);
  const view = new DataView(module.HEAPU8.buffer);
  const byMatch = new Map<number, RegexMatchResult>();
  const captures = new Map<number, CaptureResult[]>();
  const previews = new ValuePreviewBudget();
  for (let index = 0; index < native.recordCount; index += 1) {
    const pointer = buffers.recordsPointer + index * MATCH_RECORD_BYTES;
    const matchNumber = view.getUint32(pointer, true);
    const groupNumber = view.getUint32(pointer + 4, true);
    const startByte = view.getUint32(pointer + 8, true);
    const endByte = view.getUint32(pointer + 12, true);
    if (groupNumber > native.captureCount || matchNumber > native.matchCount) {
      throw new Error("PCRE2 returned an invalid match record.");
    }
    if (startByte === UNSET_OFFSET && endByte === UNSET_OFFSET) {
      if (groupNumber === 0) {
        throw new Error("PCRE2 returned an unset complete-match range.");
      }
      const rows = captures.get(matchNumber) ?? [];
      rows.push({
        groupNumber,
        ...(names.get(groupNumber)
          ? { groupName: names.get(groupNumber) }
          : {}),
        status: "did-not-participate",
      });
      captures.set(matchNumber, rows);
      continue;
    }
    const startUtf16 = utf8ByteToUtf16(subjectMap, startByte);
    const endUtf16 = utf8ByteToUtf16(subjectMap, endByte);
    const value = request.subject.slice(startUtf16, endUtf16);
    const preview = previews.take(value);
    const range = { startUtf16, endUtf16 };
    const nativeRange = {
      start: startByte,
      end: endByte,
      unit: "utf8-byte" as const,
    };
    if (groupNumber === 0) {
      byMatch.set(matchNumber, {
        matchNumber,
        value: preview.value,
        valueStatus: preview.truncated ? "truncated" : "complete",
        range,
        nativeRange,
        captures: [],
      });
    } else {
      const rows = captures.get(matchNumber) ?? [];
      rows.push({
        groupNumber,
        ...(names.get(groupNumber)
          ? { groupName: names.get(groupNumber) }
          : {}),
        value: preview.value,
        status: preview.truncated
          ? "truncated"
          : value.length === 0
            ? "matched-empty"
            : "participated",
        range,
        nativeRange,
      });
      captures.set(matchNumber, rows);
    }
  }
  const matches = [...byMatch.values()]
    .sort((left, right) => left.matchNumber - right.matchNumber)
    .map((match) => ({
      ...match,
      captures: (captures.get(match.matchNumber) ?? []).sort(
        (left, right) => left.groupNumber - right.groupNumber,
      ),
    }));
  if (matches.length !== native.matchCount) {
    throw new Error("PCRE2 returned an incomplete complete-match record set.");
  }
  return { matches, valuesTruncated: previews.truncated };
}

function emptyExecution(
  info: RegexEngineInfo,
  flags: RegexExecutionFlags,
  start: number,
  diagnostic: RegexDiagnostic,
): RegexExecutionResult {
  return {
    accepted: false,
    engine: info,
    flags,
    matches: [],
    diagnostics: [diagnostic],
    elapsedMs: performance.now() - start,
    truncated: false,
  };
}

export class Pcre2EngineAdapter implements RegexEngineAdapter {
  readonly flavour = "pcre2" as const;
  readonly #module: Pcre2EmscriptenModule;
  readonly #info: RegexEngineInfo;

  constructor(module: Pcre2EmscriptenModule, runtimeVersion?: string) {
    this.#module = module;
    this.#info = pcre2EngineInfo(runtimeVersion);
  }

  async load(): Promise<RegexEngineInfo> {
    if (
      this.#module._regex_pcre2_bridge_abi_version() !==
        PCRE2_BRIDGE_ABI_VERSION ||
      this.#module._regex_pcre2_config_flags() !== 1 ||
      this.#module.UTF8ToString(this.#module._regex_pcre2_version()) !==
        PCRE2_ENGINE_VERSION ||
      this.#module._regex_pcre2_self_test() !== 0
    ) {
      throw new Error(
        "The bundled PCRE2 engine failed its identity or bridge self-test.",
      );
    }
    return this.#info;
  }

  async execute(request: RegexExecutionRequest): Promise<RegexExecutionResult> {
    const result = this.#run(request);
    if (!("execution" in result)) return result;
    throw new Error("PCRE2 execution returned a replacement result.");
  }

  async replace(
    request: RegexReplacementRequest,
  ): Promise<RegexReplacementResult> {
    const result = this.#run(request, request);
    if ("execution" in result) return result;
    throw new Error("PCRE2 replacement returned an execution-only result.");
  }

  #run(
    request: RegexExecutionRequest,
    replacementRequest?: RegexReplacementRequest,
  ): RegexExecutionResult | RegexReplacementResult {
    if (request.flavour !== "pcre2") {
      throw new Error(`PCRE2 adapter cannot execute ${request.flavour}.`);
    }
    if (
      request.flavourVersion !== undefined &&
      !PCRE2_COMPATIBLE_FLAVOUR_VERSIONS.has(request.flavourVersion)
    ) {
      throw new RangeError(
        `PCRE2 version ${JSON.stringify(request.flavourVersion)} is unsupported by this engine.`,
      );
    }
    const start = performance.now();
    const flags = normalizedPcre2Flags(request.flags, request.scanAll);
    const patternMap = buildUtf8OffsetMap(request.pattern);
    const subjectMap = buildUtf8OffsetMap(request.subject);
    const invalidUnicode =
      containsLoneSurrogate(request.pattern, "Pattern") ??
      containsLoneSurrogate(request.subject, "Subject") ??
      (replacementRequest
        ? containsLoneSurrogate(replacementRequest.replacement, "Replacement")
        : undefined);
    if (invalidUnicode) {
      return emptyExecution(this.#info, flags, start, invalidUnicode);
    }
    const pattern = TEXT_ENCODER.encode(request.pattern);
    const subject = TEXT_ENCODER.encode(request.subject);
    const replacement = replacementRequest
      ? TEXT_ENCODER.encode(replacementRequest.replacement)
      : undefined;
    validateRequestBounds(
      request,
      pattern.byteLength,
      subject.byteLength,
      replacementRequest && replacement
        ? {
            bytes: replacement.byteLength,
            maximumOutputBytes: replacementRequest.maximumOutputBytes,
          }
        : undefined,
    );
    if (
      replacementRequest &&
      replacementRequest.replacement.length >
        DEFAULT_REGEX_LIMITS.maximumReplacementTemplateUtf16
    ) {
      throw new RangeError(
        `Replacement template exceeds the ${DEFAULT_REGEX_LIMITS.maximumReplacementTemplateUtf16.toLocaleString()} UTF-16 unit limit.`,
      );
    }
    const limits = pcre2Limits(request.options);
    const allocations = new WasmAllocations(this.#module);
    try {
      const patternPointer = allocations.encoded(pattern);
      const subjectPointer = allocations.encoded(subject);
      const replacementPointer = replacement
        ? allocations.encoded(replacement)
        : 0;
      const limitsPointer = allocations.allocate(LIMIT_BYTES);
      const recordCapacity =
        request.maximumMatches + request.maximumCaptureRows;
      const recordsPointer = allocations.allocate(
        recordCapacity * MATCH_RECORD_BYTES,
      );
      const nameCapacity = DEFAULT_REGEX_LIMITS.maximumCaptureGroups;
      const namesPointer = allocations.allocate(
        nameCapacity * NAME_RECORD_BYTES,
      );
      const nameBytesPointer = allocations.allocate(NAME_BYTES_CAPACITY);
      const outputPointer = replacementRequest
        ? allocations.allocate(replacementRequest.maximumOutputBytes + 1)
        : 0;
      const resultPointer = allocations.allocate(RESULT_BYTES);
      this.#module.HEAPU8.fill(0, resultPointer, resultPointer + RESULT_BYTES);
      writeLimits(this.#module, limitsPointer, request, limits);
      const buffers: NativeBuffers = {
        recordsPointer,
        namesPointer,
        nameBytesPointer,
        outputPointer,
        resultPointer,
        recordCapacity,
      };
      if (replacementRequest && replacement) {
        this.#module._regex_pcre2_substitute(
          patternPointer,
          pattern.byteLength,
          subjectPointer,
          subject.byteLength,
          replacementPointer,
          replacement.byteLength,
          pcre2ApplicationFlags(flags),
          limitsPointer,
          recordsPointer,
          recordCapacity,
          namesPointer,
          nameCapacity,
          nameBytesPointer,
          NAME_BYTES_CAPACITY,
          outputPointer,
          replacementRequest.maximumOutputBytes,
          resultPointer,
        );
      } else {
        this.#module._regex_pcre2_execute(
          patternPointer,
          pattern.byteLength,
          subjectPointer,
          subject.byteLength,
          pcre2ApplicationFlags(flags),
          limitsPointer,
          recordsPointer,
          recordCapacity,
          namesPointer,
          nameCapacity,
          nameBytesPointer,
          NAME_BYTES_CAPACITY,
          resultPointer,
        );
      }
      const native = runResult(this.#module, resultPointer);
      validateNativeBounds(
        native,
        buffers,
        replacementRequest?.maximumOutputBytes,
      );
      if (native.status !== 0) {
        return emptyExecution(
          this.#info,
          flags,
          start,
          diagnosticForFailure(this.#module, native, patternMap),
        );
      }
      const materialized = materializeMatches(
        this.#module,
        buffers,
        native,
        request,
        subjectMap,
      );
      const diagnostics: RegexDiagnostic[] = [];
      if (native.resultsTruncated) {
        diagnostics.push({
          id: "pcre2-results-truncated",
          source: "execution-engine",
          severity: "warning",
          code: "result-limit",
          message: `Results reached the configured limit (${request.maximumMatches.toLocaleString()} matches or ${request.maximumCaptureRows.toLocaleString()} capture rows).`,
          flavour: "pcre2",
          provenance: "derived",
        });
      }
      if (native.namesTruncated) {
        diagnostics.push({
          id: "pcre2-capture-names-truncated",
          source: "execution-engine",
          severity: "warning",
          code: "capture-name-limit",
          message:
            "Some PCRE2 capture names exceeded the bounded metadata buffer.",
          flavour: "pcre2",
          provenance: "derived",
        });
      }
      if (materialized.valuesTruncated) {
        diagnostics.push({
          id: "pcre2-value-previews-truncated",
          source: "execution-engine",
          severity: "warning",
          code: "result-value-preview-limit",
          message:
            "Displayed PCRE2 result values were clipped to bounded previews; exact byte and UTF-16 ranges are retained.",
          flavour: "pcre2",
          provenance: "derived",
        });
      }
      const execution: RegexExecutionResult = {
        accepted: true,
        engine: this.#info,
        flags,
        matches: materialized.matches,
        diagnostics,
        elapsedMs: performance.now() - start,
        truncated: native.resultsTruncated,
      };
      if (!replacementRequest) return execution;
      const output = TEXT_DECODER.decode(
        this.#module.HEAPU8.slice(
          outputPointer,
          outputPointer + native.outputLength,
        ),
      );
      const executionWithOutputDiagnostic: RegexExecutionResult =
        native.outputTruncated
          ? {
              ...execution,
              diagnostics: [
                ...execution.diagnostics,
                {
                  id: "pcre2-output-truncated",
                  source: "execution-engine",
                  severity: "warning",
                  code: "replacement-output-limit",
                  message: `Replacement preview was truncated at ${replacementRequest.maximumOutputBytes.toLocaleString()} UTF-8 bytes.`,
                  flavour: "pcre2",
                  provenance: "derived",
                },
              ],
            }
          : execution;
      return {
        execution: executionWithOutputDiagnostic,
        output,
        outputBytes: native.outputLength,
        outputTruncated: native.outputTruncated,
        truncated: native.outputTruncated || native.resultsTruncated,
      };
    } finally {
      allocations.free();
    }
  }

  terminate(): void {
    // Lifecycle termination is performed by killing the containing worker.
  }
}
