import { Injectable, OnModuleInit, OnModuleDestroy, Logger } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import { Kafka, Producer, logLevel } from 'kafkajs'
import { IDomainEvent } from '@/domain/events'

@Injectable()
export class EventPublisherService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(EventPublisherService.name)
  private kafka: Kafka
  private producer: Producer

  constructor(private readonly configService: ConfigService) {
    const brokers = this.configService.get<string>('KAFKA_BROKERS', 'localhost:9092').split(',')
    const clientId = this.configService.get<string>('KAFKA_CLIENT_ID', 'authorization-service')

    this.kafka = new Kafka({
      clientId,
      brokers,
      logLevel: logLevel.WARN,
    })

    this.producer = this.kafka.producer()
  }

  async onModuleInit() {
    try {
      await this.producer.connect()
      this.logger.log('Kafka producer connected')
    } catch (error) {
      this.logger.error('Failed to connect Kafka producer:', error)
    }
  }

  async onModuleDestroy() {
    await this.producer.disconnect()
    this.logger.log('Kafka producer disconnected')
  }

  async publish(event: IDomainEvent): Promise<void> {
    try {
      const topic = this.getTopicFromEventType(event.eventType)
      await this.producer.send({
        topic,
        messages: [
          {
            key: event.aggregateId,
            value: JSON.stringify({
              eventId: event.eventId,
              eventType: event.eventType,
              aggregateId: event.aggregateId,
              occurredAt: event.occurredAt.toISOString(),
              payload: event.payload,
            }),
            timestamp: event.occurredAt.getTime().toString(),
          },
        ],
      })
      this.logger.debug(`Event published: ${event.eventType}`)
    } catch (error) {
      this.logger.error(`Failed to publish event: ${event.eventType}`, error)
      throw error
    }
  }

  async publishAll(events: IDomainEvent[]): Promise<void> {
    for (const event of events) {
      await this.publish(event)
    }
  }

  private getTopicFromEventType(eventType: string): string {
    // eventType format: "authorization.role.authorized"
    // topic: "authorization-events"
    const parts = eventType.split('.')
    return `${parts[0]}-events`
  }
}
