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

// 定义 Kafka 消息接口
export interface DomainEventMessage {
  eventId: string;
  eventType: string;
  occurredAt: string;
  aggregateId: string;
  aggregateType: string;
  payload: any;
}

// 定义主题常量 - identity-service 发布的事件
export const IDENTITY_TOPICS = {
  USER_ACCOUNT_CREATED: 'identity.UserAccountCreated',
  USER_ACCOUNT_AUTO_CREATED: 'identity.UserAccountAutoCreated',
  DEVICE_ADDED: 'identity.DeviceAdded',
  DEVICE_REMOVED: 'identity.DeviceRemoved',
  PHONE_BOUND: 'identity.PhoneBound',
  WALLET_BOUND: 'identity.WalletBound',
  MULTIPLE_WALLETS_BOUND: 'identity.MultipleWalletsBound',
  KYC_SUBMITTED: 'identity.KYCSubmitted',
  KYC_VERIFIED: 'identity.KYCVerified',
  KYC_REJECTED: 'identity.KYCRejected',
  KYC_APPROVED: 'identity.KYCApproved',
  USER_LOCATION_UPDATED: 'identity.UserLocationUpdated',
  USER_ACCOUNT_FROZEN: 'identity.UserAccountFrozen',
  ACCOUNT_FROZEN: 'identity.AccountFrozen',
  USER_ACCOUNT_DEACTIVATED: 'identity.UserAccountDeactivated',
  // MPC 请求发送到 mpc.* topic，让 mpc-service 消费
  MPC_KEYGEN_REQUESTED: 'mpc.KeygenRequested',
  MPC_SIGNING_REQUESTED: 'mpc.SigningRequested',
} as const;

// 定义 identity-service 需要消费的 MPC 事件主题
export const MPC_CONSUME_TOPICS = {
  KEYGEN_COMPLETED: 'mpc.KeygenCompleted',
  SESSION_FAILED: 'mpc.SessionFailed',
} as const;

@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',
      'identity-service',
    );

    this.logger.log(`[INIT] Kafka EventPublisher initializing...`);
    this.logger.log(`[INIT] ClientId: ${clientId}`);
    this.logger.log(`[INIT] Brokers: ${brokers.join(', ')}`);

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

  async onModuleInit() {
    this.logger.log(`[CONNECT] Connecting Kafka producer...`);
    await this.producer.connect();
    this.logger.log(`[CONNECT] Kafka producer connected successfully`);
  }

  async onModuleDestroy() {
    this.logger.log(`[DISCONNECT] Disconnecting Kafka producer...`);
    await this.producer.disconnect();
    this.logger.log(`[DISCONNECT] Kafka producer disconnected`);
  }

  async publish(event: DomainEvent): Promise<void>;
  async publish(topic: string, message: DomainEventMessage): Promise<void>;
  async publish(
    eventOrTopic: DomainEvent | string,
    message?: DomainEventMessage,
  ): Promise<void> {
    if (typeof eventOrTopic === 'string') {
      // 直接发布到指定 topic (用于重试场景)
      const topic = eventOrTopic;
      const msg = message!;

      this.logger.log(`[PUBLISH] Publishing to topic: ${topic}`);
      this.logger.debug(`[PUBLISH] Message: ${JSON.stringify(msg)}`);

      await this.producer.send({
        topic,
        messages: [
          {
            key: msg.eventId,
            value: JSON.stringify(msg),
          },
        ],
      });

      this.logger.log(
        `[PUBLISH] Successfully published eventId=${msg.eventId} to ${topic}`,
      );
    } else {
      // 从领域事件发布
      const event = eventOrTopic;
      const topic = this.getTopicForEvent(event);
      const payload = (event as any).payload;

      this.logger.log(
        `[PUBLISH] Publishing event: type=${event.eventType}, topic=${topic}`,
      );
      this.logger.log(`[PUBLISH] EventId: ${event.eventId}`);
      this.logger.debug(`[PUBLISH] Payload: ${JSON.stringify(payload)}`);

      const messageValue = {
        eventId: event.eventId,
        eventType: event.eventType,
        occurredAt: event.occurredAt.toISOString(),
        aggregateId: (event as any).aggregateId || '',
        aggregateType: (event as any).aggregateType || 'UserAccount',
        payload,
      };

      await this.producer.send({
        topic,
        messages: [
          {
            key: event.eventId,
            value: JSON.stringify(messageValue),
          },
        ],
      });

      this.logger.log(
        `[PUBLISH] Successfully published ${event.eventType} to ${topic}`,
      );
    }
  }

  /**
   * 根据事件类型获取对应的 Kafka topic
   * MPC 相关事件发送到 mpc.* topic，其他事件发送到 identity.* topic
   */
  private getTopicForEvent(event: DomainEvent): string {
    const eventType = event.eventType;

    // MPC 相关事件使用 mpc.* 前缀
    if (eventType === 'MpcKeygenRequested') {
      return IDENTITY_TOPICS.MPC_KEYGEN_REQUESTED;
    }
    if (eventType === 'MpcSigningRequested') {
      return IDENTITY_TOPICS.MPC_SIGNING_REQUESTED;
    }

    // 其他事件使用 identity.* 前缀
    return `identity.${eventType}`;
  }

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