import type { RegexEngineCapabilities } from "../../../model/flavour";
import {
  PortableEngineAdapter,
  type PortableBridgeRequest,
  type PortableRegexBridge,
} from "../portable/PortableEngineAdapter";
import type { CppRegexModule } from "./cpp-module";

export const CPP_ENGINE_VERSION = "Emscripten 6.0.4 libc++ std::wregex";
export const CPP_FLAVOUR_VERSION = "C++ std::regex · Emscripten 6.0.4 libc++";

const CAPABILITIES: RegexEngineCapabilities = {
  compilation: true,
  matching: true,
  replacement: true,
  namedCaptures: false,
  captureHistory: false,
  actualTrace: false,
  benchmark: false,
};

class CppBridge implements PortableRegexBridge {
  readonly #module: CppRegexModule;

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

  load(): Promise<Readonly<Record<string, unknown>>> {
    return Promise.resolve(this.#module.regexToolsCppIdentity());
  }

  run(request: PortableBridgeRequest): Promise<unknown> {
    return Promise.resolve(this.#module.regexToolsCppRun(request));
  }
}

export class CppEngineAdapter extends PortableEngineAdapter {
  constructor(module: CppRegexModule, runtimeIdentity?: string) {
    super(new CppBridge(module), {
      flavour: "cpp",
      flavourLabel: "C++ std::regex",
      expectedFlavourVersion: CPP_FLAVOUR_VERSION,
      engineName: "C++ std::wregex (Emscripten libc++)",
      engineVersion: CPP_ENGINE_VERSION,
      runtimeVersion: [
        "WebAssembly",
        "32-bit wchar_t code-point bridge",
        runtimeIdentity,
      ]
        .filter(Boolean)
        .join(" · "),
      offsetUnit: "code-point",
      supportedFlags: "ginoc",
      capabilities: CAPABILITIES,
      rejectLoneSurrogates: true,
      validateOptions: (options) => {
        const keys = Object.keys(options);
        const grammar = options.grammar;
        if (
          keys.length !== 1 ||
          keys[0] !== "grammar" ||
          typeof grammar !== "string" ||
          !["ECMAScript", "basic", "extended", "awk", "grep", "egrep"].includes(
            grammar,
          )
        ) {
          throw new RangeError(
            "C++ std::regex requires one supported grammar option.",
          );
        }
      },
      validateIdentity: (identity) => {
        if (
          identity.implementation !== "libc++ std::wregex" ||
          identity.emscripten !== "6.0.4" ||
          identity.wcharBits !== 32 ||
          identity.replacementSelfTest !== true
        ) {
          throw new Error(
            "The bundled C++ runtime failed its identity self-test.",
          );
        }
      },
    });
  }
}
