import {
  PORTABLE_BRIDGE_ABI_VERSION,
  PortableEngineAdapter,
  type PortableEngineConfiguration,
  type PortableRegexBridge,
} from "../portable/PortableEngineAdapter";

export const GO_FLAVOUR_VERSION = "Go 1.26.5 standard-library regexp";
export const GO_ENGINE_VERSION = "1.26.5";
export const GO_RUNTIME_VERSION = "go1.26.5 js/wasm";

function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

function configuration(runtimeIdentity?: string): PortableEngineConfiguration {
  return {
    flavour: "go",
    flavourLabel: "Go regexp",
    expectedFlavourVersion: GO_FLAVOUR_VERSION,
    engineName: "Go standard-library regexp",
    engineVersion: GO_ENGINE_VERSION,
    runtimeVersion: [GO_RUNTIME_VERSION, runtimeIdentity]
      .filter(Boolean)
      .join(" · "),
    offsetUnit: "utf8-byte",
    supportedFlags: "gimsU",
    rejectLoneSurrogates: true,
    capabilities: {
      compilation: true,
      matching: true,
      replacement: true,
      namedCaptures: true,
      captureHistory: false,
      actualTrace: false,
      benchmark: false,
    },
    validateIdentity: (envelope) => {
      const identity = envelope.identity;
      if (
        envelope.abi !== PORTABLE_BRIDGE_ABI_VERSION ||
        envelope.ok !== true ||
        !isRecord(identity) ||
        identity.bridge !== "regex-tools-go-json" ||
        identity.bridgeVersion !== PORTABLE_BRIDGE_ABI_VERSION ||
        identity.engine !== "Go standard-library regexp" ||
        identity.engineVersion !== GO_ENGINE_VERSION ||
        identity.goVersion !== "go1.26.5" ||
        identity.package !== "regexp" ||
        identity.offsetUnit !== "utf8-byte" ||
        identity.selfTest !== true
      ) {
        throw new Error(
          "The bundled Go regexp runtime failed its identity self-test.",
        );
      }
    },
  };
}

export class GoEngineAdapter extends PortableEngineAdapter {
  constructor(bridge: PortableRegexBridge, runtimeIdentity?: string) {
    super(bridge, configuration(runtimeIdentity));
  }
}
