import type { IJobQueue } from "./job-queue.interface";

export type InMemoryHandler = (input: unknown) => Promise<void> | void;

export class InMemoryJobQueue implements IJobQueue {
  private counter = 0;
  private readonly handlers: Record<string, InMemoryHandler>;

  constructor(handlers: Record<string, InMemoryHandler> = {}) {
    this.handlers = { ...handlers };
  }

  register(slug: string, handler: InMemoryHandler): void {
    this.handlers[slug] = handler;
  }

  async enqueue<T>(
    taskSlug: string,
    input: T,
    options?: { runAt?: Date },
  ): Promise<{ jobId: string }> {
    const handler = this.handlers[taskSlug];
    if (!handler) {
      throw new Error(`no handler registered for task slug: ${taskSlug}`);
    }
    this.counter += 1;
    const jobId = `in-memory-${this.counter}`;
    const delay = options?.runAt ? options.runAt.getTime() - Date.now() : 0;
    if (delay > 0) {
      setTimeout(() => void handler(input), delay);
    } else {
      setImmediate(() => void handler(input));
    }
    return { jobId };
  }
}
