import { Injectable } from '@nestjs/common';
import {
  UserRegisteredEvent,
  UserLoggedInEvent,
  UserLoggedOutEvent,
  PasswordChangedEvent,
  AccountLockedEvent,
  PhoneChangedEvent,
  PasswordResetEvent,
} from '../../domain/events/auth.events';

/**
 * Event publisher using Outbox pattern.
 * Events are written to the outbox table within the same DB transaction,
 * then published to Kafka by the OutboxRelay or Debezium CDC.
 */
@Injectable()
export class EventPublisherService {
  async publishUserRegistered(event: UserRegisteredEvent): Promise<void> {
    // In Phase 1, we use direct Kafka publish.
    // In production, this would use OutboxService.publishWithinTransaction()
    // to ensure atomicity with the user creation.
    await this.publishToOutbox('genex.user.registered', 'User', event.userId, 'user.registered', event);
  }

  async publishUserLoggedIn(event: UserLoggedInEvent): Promise<void> {
    await this.publishToOutbox('genex.user.logged-in', 'User', event.userId, 'user.logged_in', event);
  }

  async publishUserLoggedOut(event: UserLoggedOutEvent): Promise<void> {
    await this.publishToOutbox('genex.user.logged-out', 'User', event.userId, 'user.logged_out', event);
  }

  async publishPasswordChanged(event: PasswordChangedEvent): Promise<void> {
    await this.publishToOutbox('genex.user.password-changed', 'User', event.userId, 'user.password_changed', event);
  }

  async publishAccountLocked(event: AccountLockedEvent): Promise<void> {
    await this.publishToOutbox('genex.user.locked', 'User', event.userId, 'user.account_locked', event);
  }

  async publishPhoneChanged(event: PhoneChangedEvent): Promise<void> {
    await this.publishToOutbox('genex.user.phone-changed', 'User', event.userId, 'user.phone_changed', event);
  }

  async publishPasswordReset(event: PasswordResetEvent): Promise<void> {
    await this.publishToOutbox('genex.user.password-reset', 'User', event.userId, 'user.password_reset', event);
  }

  private async publishToOutbox(
    topic: string,
    aggregateType: string,
    aggregateId: string,
    eventType: string,
    payload: any,
  ): Promise<void> {
    // This will be wired to OutboxService in the module setup
    // For now, stores the event intent. The actual Kafka publish happens via OutboxRelay.
    if (this.outboxService) {
      await this.outboxService.publish({
        aggregateType,
        aggregateId,
        eventType,
        topic,
        payload,
      });
    }
  }

  private outboxService: any;

  setOutboxService(outboxService: any): void {
    this.outboxService = outboxService;
  }
}
