/**
 * Planting Event Consumer Service for Wallet Service
 *
 * Consumes planting events from planting-service via Kafka.
 * When a user plants a tree, settles their pending rewards.
 */

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

export const PLANTING_TOPICS = {
  PLANTING_EVENTS: 'planting-events',
} as const;

export interface PlantingCreatedPayload {
  orderNo: string;
  accountSequence: string;
  userId: string;
  treeCount: number;
  totalAmount: string;
  createdAt: string;
}

export type PlantingEventHandler = (payload: PlantingCreatedPayload) => Promise<void>;

@Injectable()
export class PlantingEventConsumerService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(PlantingEventConsumerService.name);
  private kafka: Kafka;
  private consumer: Consumer;
  private isConnected = false;

  private plantingCreatedHandler?: PlantingEventHandler;

  constructor(private readonly configService: ConfigService) {}

  async onModuleInit() {
    const brokers = this.configService.get<string>('KAFKA_BROKERS')?.split(',') || ['localhost:9092'];
    const clientId = this.configService.get<string>('KAFKA_CLIENT_ID') || 'wallet-service';
    const groupId = 'wallet-service-planting-events';

    this.logger.log(`[INIT] Planting Event Consumer initializing...`);
    this.logger.log(`[INIT] ClientId: ${clientId}`);
    this.logger.log(`[INIT] GroupId: ${groupId}`);
    this.logger.log(`[INIT] Brokers: ${brokers.join(', ')}`);
    this.logger.log(`[INIT] Topics: ${Object.values(PLANTING_TOPICS).join(', ')}`);

    // 企业级重试配置：指数退避，最多重试约 2.5 小时
    this.kafka = new Kafka({
      clientId: `${clientId}-planting`,
      brokers,
      logLevel: logLevel.WARN,
      retry: {
        initialRetryTime: 1000,        // 1 秒
        maxRetryTime: 300000,          // 最大 5 分钟
        retries: 15,                   // 最多 15 次
        multiplier: 2,                 // 指数退避因子
        restartOnFailure: async () => true,
      },
    });

    this.consumer = this.kafka.consumer({
      groupId,
      sessionTimeout: 30000,
      heartbeatInterval: 3000,
    });

    try {
      this.logger.log(`[CONNECT] Connecting Planting Event consumer...`);
      await this.consumer.connect();
      this.isConnected = true;
      this.logger.log(`[CONNECT] Planting Event consumer connected successfully`);

      await this.consumer.subscribe({
        topics: Object.values(PLANTING_TOPICS),
        fromBeginning: false,
      });
      this.logger.log(`[SUBSCRIBE] Subscribed to planting topics`);

      await this.startConsuming();
    } catch (error) {
      this.logger.error(`[ERROR] Failed to connect Planting Event consumer`, error);
    }
  }

  async onModuleDestroy() {
    if (this.isConnected) {
      await this.consumer.disconnect();
      this.logger.log('Planting Event consumer disconnected');
    }
  }

  /**
   * Register handler for planting created events
   */
  onPlantingCreated(handler: PlantingEventHandler): void {
    this.plantingCreatedHandler = handler;
    this.logger.log(`[REGISTER] PlantingCreated handler registered`);
  }

  private async startConsuming(): Promise<void> {
    await this.consumer.run({
      eachMessage: async ({ topic, partition, message }: EachMessagePayload) => {
        const offset = message.offset;
        this.logger.log(`[RECEIVE] Message received: topic=${topic}, partition=${partition}, offset=${offset}`);

        try {
          const value = message.value?.toString();
          if (!value) {
            this.logger.warn(`[RECEIVE] Empty message received on ${topic}`);
            return;
          }

          this.logger.debug(`[RECEIVE] Raw message: ${value.substring(0, 500)}...`);

          const parsed = JSON.parse(value);
          // 兼容多种事件格式: eventType, type, eventName
          const eventType = parsed.eventType || parsed.type || parsed.eventName;
          // 兼容多种数据格式: payload, data, 或直接在根级别
          const payload = parsed.payload || parsed.data || parsed;

          this.logger.log(`[RECEIVE] Event type: ${eventType}`);

          // 监听认种支付完成事件 - 用户认种后，结算其所有待领取奖励
          // 支持: PlantingOrderPaid, PlantingOrderCreated, planting.planting.created
          if (eventType === 'PlantingOrderPaid' || eventType === 'planting.planting.created' || eventType === 'PlantingOrderCreated') {
            this.logger.log(`[HANDLE] Processing PlantingPaid event`);
            this.logger.log(`[HANDLE] orderNo: ${payload.orderNo}`);
            this.logger.log(`[HANDLE] accountSequence: ${payload.accountSequence}`);
            this.logger.log(`[HANDLE] userId: ${payload.userId}`);
            this.logger.log(`[HANDLE] treeCount: ${payload.treeCount}`);

            if (this.plantingCreatedHandler) {
              await this.plantingCreatedHandler(payload as PlantingCreatedPayload);
              this.logger.log(`[HANDLE] PlantingCreated handler completed`);
            } else {
              this.logger.warn(`[HANDLE] No handler registered for PlantingCreated`);
            }
          } else {
            this.logger.debug(`[RECEIVE] Ignoring event type: ${eventType}`);
          }
        } catch (error) {
          this.logger.error(`[ERROR] Error processing planting event from ${topic}`, error);
          // Re-throw to trigger Kafka retry mechanism
          // This ensures messages are not marked as consumed until successfully processed
          throw error;
        }
      },
    });

    this.logger.log(`[START] Started consuming planting events`);
  }
}
