/**
 * Dependency Injection Container
 * 
 * Supports three lifecycle types:
 * - singleton: One instance for the entire application
 * - transient: New instance every time
 * - scoped: One instance per scope (e.g., per request)
 */
class Container {
  constructor() {
    this.services = new Map();      // Singleton instances tárolása
    this.factories = new Map();     // Factory függvények tárolása
    this.lifetimes = new Map();     // Lifecycle típusok tárolása
  }

  /**
   * Service regisztráció
   * 
   * @param {string} name - Service neve
   * @param {Function} factory - Factory függvény ami az instance-t létrehozza
   * @param {string} lifetime - 'singleton' | 'transient' | 'scoped'
   */
  register(name, factory, lifetime = 'singleton') {
    // Factory és lifetime tárolása
    this.factories.set(name, factory);
    this.lifetimes.set(name, lifetime);

    // Ha singleton, azonnal példányosítjuk
    if (lifetime === 'singleton') {
      const instance = factory(this);
      this.services.set(name, instance);
    }
  }

  /**
   * Singleton service regisztráció (kényelmi függvény)
   * 
   * @param {string} name - Service neve
   * @param {Function} factory - Factory függvény ami az instance-t létrehozza
   */
  registerSingleton(name, factory) {
    this.register(name, factory, 'singleton');
  }

  /**
   * Transient service regisztráció (kényelmi függvény)
   * 
   * @param {string} name - Service neve
   * @param {Function} factory - Factory függvény ami az instance-t létrehozza
   */
  registerTransient(name, factory) {
    this.register(name, factory, 'transient');
  }

  /**
   * Scoped service regisztráció (kényelmi függvény)
   * 
   * @param {string} name - Service neve
   * @param {Function} factory - Factory függvény ami az instance-t létrehozza
   */
  registerScoped(name, factory) {
    this.register(name, factory, 'scoped');
  }

  /**
   * Service feloldás
   * 
   * @param {string} name - Service neve
   * @param {Map} scope - Scoped instance-ok tárolója (opcionális)
   * @returns {*} Service instance
   */
  resolve(name, scope = null) {
    // Ellenőrizzük hogy regisztrálva van-e
    if (!this.factories.has(name)) {
      throw new Error(`Service '${name}' is not registered`);
    }

    const lifetime = this.lifetimes.get(name);

    // SCOPED: Scope-ból vagy új instance
    if (lifetime === 'scoped' && scope) {
      if (scope.has(name)) {
        return scope.get(name);
      }
      const instance = this.factories.get(name)(this);
      scope.set(name, instance);
      return instance;
    }

    // SINGLETON: Visszaadjuk a tárolt instance-t
    if (lifetime === 'singleton') {
      return this.services.get(name);
    }

    // TRANSIENT: Mindig új instance
    if (lifetime === 'transient') {
      return this.factories.get(name)(this);
    }

    // Default: singleton behavior
    return this.services.get(name);
  }

  /**
   * Új scope létrehozása
   * 
   * @returns {Object} Scope objektum resolve metódussal
   */
  createScope() {
    const scopeMap = new Map();
    
    return {
      resolve: (name) => this.resolve(name, scopeMap),
      dispose: () => {
        // Scope-beli instance-ok felszabadítása
        scopeMap.clear();
      }
    };
  }

  /**
   * Ellenőrzi hogy egy service regisztrálva van-e
   * 
   * @param {string} name - Service neve
   * @returns {boolean}
   */
  has(name) {
    return this.factories.has(name);
  }

  /**
   * Service törlése a containerből
   * 
   * @param {string} name - Service neve
   */
  unregister(name) {
    this.services.delete(name);
    this.factories.delete(name);
    this.lifetimes.delete(name);
  }

  /**
   * Az összes service listázása
   * 
   * @returns {Array<{name: string, lifetime: string}>}
   */
  list() {
    const services = [];
    for (const [name, lifetime] of this.lifetimes.entries()) {
      services.push({ name, lifetime });
    }
    return services;
  }
}

export { Container };
