/**
 * Infrastructure Adapter: InMemoryMediaEventPublisher
 * 
 * In-memory implementation of MediaEventPublisher for testing purposes.
 * Stores events in memory for verification in integration tests.
 */

import type { Logger } from '@core/shared/domain/Logger';
import type { DomainEvent } from '@core/shared/domain/DomainEvent';

export interface MediaEvent {
  eventType: string;
  aggregateId: string;
  eventData: unknown;
  occurredAt: Date;
}

export class InMemoryMediaEventPublisher {
  private events: MediaEvent[] = [];

  constructor(private readonly logger: Logger) {
    this.logger.info('[InMemoryMediaEventPublisher] Initialized.');
  }

  /**
   * Publish a domain event
   */
  async publish(event: DomainEvent): Promise<void> {
    this.logger.debug(`[InMemoryMediaEventPublisher] Publishing event: ${event.eventType} for aggregate: ${event.aggregateId}`);
    
    const mediaEvent: MediaEvent = {
      eventType: event.eventType,
      aggregateId: event.aggregateId,
      eventData: event.eventData,
      occurredAt: event.occurredAt,
    };
    
    this.events.push(mediaEvent);
    this.logger.info(`Event ${event.eventType} published successfully.`);
  }

  /**
   * Get all published events
   */
  getEvents(): MediaEvent[] {
    return [...this.events];
  }

  /**
   * Get events by event type
   */
  getEventsByType(eventType: string): MediaEvent[] {
    return this.events.filter(event => event.eventType === eventType);
  }

  /**
   * Get events by aggregate ID
   */
  getEventsByAggregateId(aggregateId: string): MediaEvent[] {
    return this.events.filter(event => event.aggregateId === aggregateId);
  }

  /**
   * Get the total number of events
   */
  getEventCount(): number {
    return this.events.length;
  }

  /**
   * Clear all events
   */
  clear(): void {
    this.events = [];
    this.logger.info('[InMemoryMediaEventPublisher] All events cleared.');
  }

  /**
   * Check if an event of a specific type was published
   */
  hasEvent(eventType: string): boolean {
    return this.events.some(event => event.eventType === eventType);
  }

  /**
   * Check if an event was published for a specific aggregate
   */
  hasEventForAggregate(eventType: string, aggregateId: string): boolean {
    return this.events.some(
      event => event.eventType === eventType && event.aggregateId === aggregateId
    );
  }
}
