import type { RegexFlavourId } from "../model/flavour";
import { StartupBufferedWorker } from "./StartupBufferedWorker";
import type { WorkerFactory } from "./WorkerSupervisor";

export interface EngineWorkerRegistration {
  readonly flavour: RegexFlavourId;
  readonly label: string;
  readonly startupTimeoutMs: number;
  readonly createWorker: WorkerFactory;
}

export class EngineWorkerRegistry {
  readonly registrations: readonly EngineWorkerRegistration[];
  private readonly byFlavour: ReadonlyMap<
    RegexFlavourId,
    EngineWorkerRegistration
  >;

  constructor(registrations: readonly EngineWorkerRegistration[]) {
    const byFlavour = new Map<RegexFlavourId, EngineWorkerRegistration>();
    for (const registration of registrations) {
      if (byFlavour.has(registration.flavour)) {
        throw new Error(
          `Execution worker for ${registration.flavour} is registered more than once.`,
        );
      }
      byFlavour.set(registration.flavour, registration);
    }
    this.registrations = [...registrations];
    this.byFlavour = byFlavour;
  }

  get(flavour: RegexFlavourId): EngineWorkerRegistration | undefined {
    return this.byFlavour.get(flavour);
  }

  require(flavour: RegexFlavourId): EngineWorkerRegistration {
    const registration = this.get(flavour);
    if (registration) return registration;
    throw new Error(
      `No execution worker is registered for regex flavour ${JSON.stringify(flavour)}.`,
    );
  }
}

export const ENGINE_WORKER_REGISTRY = new EngineWorkerRegistry([
  {
    flavour: "ecmascript",
    label: "ECMAScript engine",
    startupTimeoutMs: 1_000,
    createWorker: () =>
      new Worker(
        new URL("../../workers/ecmascript.worker.ts", import.meta.url),
        {
          type: "module",
          name: "regex-tools-ecmascript",
        },
      ),
  },
  {
    flavour: "pcre2",
    label: "PCRE2 engine",
    startupTimeoutMs: 10_000,
    createWorker: () =>
      new Worker(new URL("../../workers/pcre2.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-pcre2",
      }),
  },
  {
    flavour: "php",
    label: "PHP preg engine",
    startupTimeoutMs: 30_000,
    createWorker: () =>
      new Worker(new URL("../../workers/php.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-php",
      }),
  },
  {
    flavour: "perl",
    label: "Perl regex engine",
    startupTimeoutMs: 30_000,
    createWorker: () =>
      new Worker(new URL("../../workers/perl.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-perl",
      }),
  },
  {
    flavour: "python",
    label: "Python re engine",
    startupTimeoutMs: 30_000,
    createWorker: () =>
      new Worker(new URL("../../workers/python.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-python",
      }),
  },
  {
    flavour: "ruby",
    label: "Ruby Regexp engine",
    startupTimeoutMs: 30_000,
    createWorker: () =>
      new Worker(new URL("../../workers/ruby.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-ruby",
      }),
  },
  {
    flavour: "java",
    label: "Java regex engine",
    startupTimeoutMs: 15_000,
    createWorker: () =>
      new Worker(new URL("../../workers/java.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-java",
      }),
  },
  {
    flavour: "cpp",
    label: "C++ std::regex engine",
    startupTimeoutMs: 10_000,
    createWorker: () =>
      new Worker(new URL("../../workers/cpp.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-cpp",
      }),
  },
  {
    flavour: "go",
    label: "Go regexp engine",
    startupTimeoutMs: 10_000,
    createWorker: () =>
      new Worker(new URL("../../workers/go.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-go",
      }),
  },
  {
    flavour: "dotnet",
    label: ".NET Regex engine",
    startupTimeoutMs: 60_000,
    createWorker: () =>
      new StartupBufferedWorker(
        new Worker(new URL("../../workers/dotnet.worker.ts", import.meta.url), {
          type: "module",
          name: "regex-tools-dotnet",
        }),
      ),
  },
  {
    flavour: "rust",
    label: "Rust regex engine",
    startupTimeoutMs: 10_000,
    createWorker: () =>
      new Worker(new URL("../../workers/rust.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-rust",
      }),
  },
  {
    flavour: "scala",
    label: "Scala/JVM regex compatibility engine",
    startupTimeoutMs: 15_000,
    createWorker: () =>
      new Worker(new URL("../../workers/scala.worker.ts", import.meta.url), {
        type: "module",
        name: "regex-tools-scala",
      }),
  },
]);
