import { Service } from './Service.js'

export class ServiceManager<KnownBindings extends Record<string, Service>> {
  /**
   * Registered bindings.
   */
  #bindings = new Map<keyof KnownBindings, KnownBindings[keyof KnownBindings]>()

  /**
   * Registers a service by a specified key.
   * @param key The key to use to lookup the service.
   * @param instance The instance of the service class.
   */
  register<Binding extends keyof KnownBindings>(key: Binding, instance: KnownBindings[Binding]): void {
    if (this.#bindings.has(key)) {
      throw new Error(`Trying to register ${String(key)} service, but it is already registered.`)
    }
    if (!instance) {
      throw new Error(`Trying to register ${String(key)} service, but the manager did not receive an instance.`)
    }
    this.#bindings.set(key, instance)
  }

  /**
   * Returns a service registered in the application.
   * If the service is not found it throws an error.
   *
   * It ensures a service is running before returning the service.
   *
   * @param key The key of the service to retrieve.
   * @returns The service for the given key.
   */
  async get<Binding extends keyof KnownBindings>(key: Binding): Promise<KnownBindings[Binding]> {
    const service = this.#bindings.get(key)
    if (!service) {
      throw new Error(`Trying to get ${String(key)} service, but it is not registered.`)
    }
    await service.start()
    return service as KnownBindings[Binding]
  }

  async unload(): Promise<void> {
    for (const service of this.#bindings.values()) {
      await service.stop()
      await service.destroy()
    }
    this.#bindings = new Map()
  }
}
