import EventEmitter from 'events';

import type { LiteralUnion } from 'type-fest';

import type { EventType } from '../store/models';

interface MyEventType extends EventEmitter {
  on(eventName: LiteralUnion<EventType, string | symbol>, listener: (...args: any[]) => void): this;
  emit(eventName: LiteralUnion<EventType, string | symbol>, ...args: any[]): boolean;
}

export const events = new EventEmitter() as MyEventType;

export const emitAsync = (event: string, ...args: any[]) => {
  return new Promise((resolve, reject) => {
    const timeout = setTimeout(() => {
      cleanup();
      reject(new Error(`Event ${event} timed out after 10000ms`));
    }, 10000);

    const cleanup = () => {
      clearTimeout(timeout);
      events.removeListener(`${event}.done`, handleDone);
      events.removeListener(`${event}.error`, handleError);
    };

    const handleDone = (...results: any[]) => {
      cleanup();
      resolve(results.length > 1 ? results : results[0]);
    };

    const handleError = (error: any) => {
      cleanup();
      reject(error);
    };
    events.once(`${event}.done`, handleDone);
    events.once(`${event}.error`, handleError);
    events.emit(event, ...args);
  });
};
