import type { ModuleEvent, ModuleEventHandler } from './types'

/**
 * Global event bus for inter-module communication
 * Provides loose coupling between modules via event-driven architecture
 */
export class ModuleEventBus {
  private listeners = new Map<string, Set<ModuleEventHandler>>()
  private eventHistory: ModuleEvent[] = []
  private maxHistorySize = 1000

  /**
   * Emit an event to all registered listeners
   */
  emit(type: string, data: any, source = 'unknown'): void {
    const event: ModuleEvent = {
      type,
      source,
      data,
      timestamp: Date.now()
    }

    // Store in history
    this.eventHistory.push(event)
    if (this.eventHistory.length > this.maxHistorySize) {
      this.eventHistory.shift()
    }

    // Notify listeners
    const listeners = this.listeners.get(type)
    if (listeners) {
      listeners.forEach(handler => {
        try {
          handler(event)
        } catch (error) {
          console.error(`Error in event handler for ${type}:`, error)
        }
      })
    }

    // Also notify wildcard listeners
    const wildcardListeners = this.listeners.get('*')
    if (wildcardListeners) {
      wildcardListeners.forEach(handler => {
        try {
          handler(event)
        } catch (error) {
          console.error(`Error in wildcard event handler:`, error)
        }
      })
    }
  }

  /**
   * Register an event listener
   */
  on(type: string, handler: ModuleEventHandler): () => void {
    if (!this.listeners.has(type)) {
      this.listeners.set(type, new Set())
    }
    
    this.listeners.get(type)!.add(handler)

    // Return unsubscribe function
    return () => this.off(type, handler)
  }

  /**
   * Remove an event listener
   */
  off(type: string, handler: ModuleEventHandler): void {
    const listeners = this.listeners.get(type)
    if (listeners) {
      listeners.delete(handler)
      if (listeners.size === 0) {
        this.listeners.delete(type)
      }
    }
  }

  /**
   * Remove all listeners for a given event type
   */
  removeAllListeners(type: string): void {
    this.listeners.delete(type)
  }

  /**
   * Clear all listeners
   */
  clear(): void {
    this.listeners.clear()
    this.eventHistory = []
  }

  /**
   * Get recent events (for debugging/monitoring)
   */
  getEventHistory(count = 50): ModuleEvent[] {
    return this.eventHistory.slice(-count)
  }

  /**
   * Get all registered event types
   */
  getEventTypes(): string[] {
    return Array.from(this.listeners.keys())
  }

  /**
   * Get listener count for an event type
   */
  getListenerCount(type: string): number {
    return this.listeners.get(type)?.size || 0
  }
}

// Global event bus instance
export const eventBus = new ModuleEventBus()

// Convenience functions
export const emit = eventBus.emit.bind(eventBus)
export const on = eventBus.on.bind(eventBus)
export const off = eventBus.off.bind(eventBus)