/// <reference lib="webworker" />
import { EcmaScriptSyntaxProvider } from "../regex/syntax/providers/ecmascript/EcmaScriptSyntaxProvider";
import { JavaSyntaxProvider } from "../regex/syntax/providers/java/JavaSyntaxProvider";
import { Pcre2SyntaxProvider } from "../regex/syntax/providers/pcre2/Pcre2SyntaxProvider";
import { PythonSyntaxProvider } from "../regex/syntax/providers/python/PythonSyntaxProvider";
import {
  WORKER_PROTOCOL_VERSION,
  workerError,
  type SyntaxWorkerOperation,
  type SyntaxWorkerResult,
  type WorkerRequest,
  type WorkerResponse,
} from "../regex/execution/worker-protocol";

const providers = {
  ecmascript: new EcmaScriptSyntaxProvider(),
  pcre2: new Pcre2SyntaxProvider(),
  python: new PythonSyntaxProvider(),
  java: new JavaSyntaxProvider(),
} as const;
const scope = self as DedicatedWorkerGlobalScope;

scope.onmessage = async (
  event: MessageEvent<WorkerRequest<SyntaxWorkerOperation>>,
) => {
  const request = event.data;
  if (request.protocolVersion !== WORKER_PROTOCOL_VERSION) return;
  let response: WorkerResponse<SyntaxWorkerResult>;
  try {
    const flavour = request.payload.request.flavour;
    const provider =
      flavour === "ecmascript"
        ? providers.ecmascript
        : flavour === "pcre2"
          ? providers.pcre2
          : flavour === "python"
            ? providers.python
            : flavour === "java"
              ? providers.java
              : undefined;
    if (!provider) {
      throw new Error(`No syntax provider is registered for ${flavour}.`);
    }
    const payload: SyntaxWorkerResult =
      request.payload.kind === "parse-pattern"
        ? {
            kind: "parse-pattern",
            result: await provider.parsePattern(request.payload.request),
          }
        : {
            kind: "parse-replacement",
            result: await provider.parseReplacement(request.payload.request),
          };
    response = {
      protocolVersion: WORKER_PROTOCOL_VERSION,
      requestId: request.requestId,
      generation: request.generation,
      ok: true,
      payload,
    };
  } catch (error) {
    response = {
      protocolVersion: WORKER_PROTOCOL_VERSION,
      requestId: request.requestId,
      generation: request.generation,
      ok: false,
      error: workerError(error),
    };
  }
  scope.postMessage(response);
};
