import { IEventLogEntry, IListenerEntry, IEventBus } from '../types/CalendarTypes';

/**
 * Central event dispatcher for calendar using DOM CustomEvents
 * Provides logging and debugging capabilities
 */
export class EventBus implements IEventBus {
  private eventLog: IEventLogEntry[] = [];
  private debug: boolean = false;
  private listeners: Set<IListenerEntry> = new Set();

  // Log configuration for different categories
  private logConfig: { [key: string]: boolean } = {
    calendar: true,
    grid: true,
    event: true,
    scroll: true,
    navigation: true,
    view: true,
    default: true
  };

  /**
   * Subscribe to an event via DOM addEventListener
   */
  on(eventType: string, handler: EventListener, options?: AddEventListenerOptions): () => void {
    document.addEventListener(eventType, handler, options);

    // Track for cleanup
    this.listeners.add({ eventType, handler, options });

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

  /**
   * Subscribe to an event once
   */
  once(eventType: string, handler: EventListener): () => void {
    return this.on(eventType, handler, { once: true });
  }

  /**
   * Unsubscribe from an event
   */
  off(eventType: string, handler: EventListener): void {
    document.removeEventListener(eventType, handler);

    // Remove from tracking
    for (const listener of this.listeners) {
      if (listener.eventType === eventType && listener.handler === handler) {
        this.listeners.delete(listener);
        break;
      }
    }
  }

  /**
   * Emit an event via DOM CustomEvent
   */
  emit(eventType: string, detail: unknown = {}): boolean {
    // Validate eventType
    if (!eventType) {
      return false;
    }

    const event = new CustomEvent(eventType, {
      detail: detail ?? {},
      bubbles: true,
      cancelable: true
    });

    // Log event with grouping
    if (this.debug) {
      this.logEventWithGrouping(eventType, detail);
    }

    this.eventLog.push({
      type: eventType,
      detail: detail ?? {},
      timestamp: Date.now()
    });

    // Emit on document (only DOM events now)
    return !document.dispatchEvent(event);
  }

  /**
   * Log event with console grouping
   */
  private logEventWithGrouping(eventType: string, _detail: unknown): void {
    // Extract category from event type (e.g., 'calendar:datechanged' → 'calendar')
    const category = this.extractCategory(eventType);

    // Only log if category is enabled
    if (!this.logConfig[category]) {
      return;
    }

    // Get category emoji and color (used for future console styling)
    this.getCategoryStyle(category);
  }

  /**
   * Extract category from event type
   */
  private extractCategory(eventType: string): string {
    if (!eventType) {
      return 'unknown';
    }

    if (eventType.includes(':')) {
      return eventType.split(':')[0];
    }

    // Fallback: try to detect category from event name patterns
    const lowerType = eventType.toLowerCase();
    if (lowerType.includes('grid') || lowerType.includes('rendered')) return 'grid';
    if (lowerType.includes('event') || lowerType.includes('sync')) return 'event';
    if (lowerType.includes('scroll')) return 'scroll';
    if (lowerType.includes('nav') || lowerType.includes('date')) return 'navigation';
    if (lowerType.includes('view')) return 'view';

    return 'default';
  }

  /**
   * Get styling for different categories
   */
  private getCategoryStyle(category: string): { emoji: string; color: string } {
    const styles: { [key: string]: { emoji: string; color: string } } = {
      calendar: { emoji: '📅', color: '#2196F3' },
      grid: { emoji: '📊', color: '#4CAF50' },
      event: { emoji: '📌', color: '#FF9800' },
      scroll: { emoji: '📜', color: '#9C27B0' },
      navigation: { emoji: '🧭', color: '#F44336' },
      view: { emoji: '👁', color: '#00BCD4' },
      default: { emoji: '📢', color: '#607D8B' }
    };

    return styles[category] || styles.default;
  }

  /**
   * Configure logging for specific categories
   */
  setLogConfig(config: { [key: string]: boolean }): void {
    this.logConfig = { ...this.logConfig, ...config };
  }

  /**
   * Get current log configuration
   */
  getLogConfig(): { [key: string]: boolean } {
    return { ...this.logConfig };
  }

  /**
   * Get event history
   */
  getEventLog(eventType?: string): IEventLogEntry[] {
    if (eventType) {
      return this.eventLog.filter(e => e.type === eventType);
    }
    return this.eventLog;
  }

  /**
   * Enable/disable debug mode
   */
  setDebug(enabled: boolean): void {
    this.debug = enabled;
  }
}
