/**
 * Глобальная шина событий для связи между компонентами
 */
export class EventBus {
  constructor() {
    this.events = new Map();
    this.onceEvents = new Set();
  }

  /**
   * Подписка на событие
   */
  on(eventName, callback, context = null) {
    if (!this.events.has(eventName)) {
      this.events.set(eventName, []);
    }

    const listener = {
      callback,
      context,
      id: this.generateId()
    };

    this.events.get(eventName).push(listener);
    
    // Возвращаем функцию для отписки
    return () => this.off(eventName, listener.id);
  }

  /**
   * Подписка на событие (выполняется только один раз)
   */
  once(eventName, callback, context = null) {
    const listenerId = this.generateId();
    this.onceEvents.add(listenerId);

    const unsubscribe = this.on(eventName, (...args) => {
      this.onceEvents.delete(listenerId);
      unsubscribe();
      callback.apply(context, args);
    }, context);

    return unsubscribe;
  }

  /**
   * Отписка от события
   */
  off(eventName, listenerId = null) {
    if (!this.events.has(eventName)) return;

    const listeners = this.events.get(eventName);

    if (listenerId) {
      // Удаляем конкретный listener
      const index = listeners.findIndex(l => l.id === listenerId);
      if (index !== -1) {
        listeners.splice(index, 1);
      }
    } else {
      // Удаляем все listeners для события
      this.events.delete(eventName);
    }

    // Очищаем пустые массивы
    if (listeners && listeners.length === 0) {
      this.events.delete(eventName);
    }
  }

  /**
   * Испускание события
   */
  emit(eventName, ...args) {
    if (!this.events.has(eventName)) return;

    const listeners = this.events.get(eventName).slice(); // Копируем массив

    listeners.forEach(listener => {
      try {
        listener.callback.apply(listener.context, args);
      } catch (error) {
        console.error(`EventBus: Error in listener for "${eventName}":`, error);
      }
    });

    return listeners.length;
  }

  /**
   * Получение количества подписчиков на событие
   */
  listenerCount(eventName) {
    return this.events.has(eventName) ? this.events.get(eventName).length : 0;
  }

  /**
   * Получение списка всех событий
   */
  eventNames() {
    return Array.from(this.events.keys());
  }

  /**
   * Очистка всех событий
   */
  clear() {
    this.events.clear();
    this.onceEvents.clear();
  }

  /**
   * Очистка событий по namespace
   */
  clearNamespace(namespace) {
    const pattern = new RegExp(`^${namespace}:`);
    
    for (const eventName of this.events.keys()) {
      if (pattern.test(eventName)) {
        this.events.delete(eventName);
      }
    }
  }

  /**
   * Генерация уникального ID
   */
  generateId() {
    return Math.random().toString(36).substr(2, 9);
  }

  /**
   * Отладочная информация
   */
  debug() {
    console.group('EventBus Debug Info');
    console.log('Events count:', this.events.size);
    console.log('Once events count:', this.onceEvents.size);
    
    for (const [eventName, listeners] of this.events) {
      console.log(`"${eventName}": ${listeners.length} listeners`);
    }
    
    console.groupEnd();
  }
}

// Создаем глобальный экземпляр
export const eventBus = new EventBus();

// Экспортируем для удобства
export default eventBus;