import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ContributionSyncService } from '../services/contribution-sync.service';
import { NetworkSyncService } from '../services/network-sync.service';
import { Kafka, Consumer, EachMessagePayload } from 'kafkajs';

@Injectable()
export class ContributionEventHandler implements OnModuleInit {
  private readonly logger = new Logger(ContributionEventHandler.name);
  private consumer: Consumer;

  constructor(
    private readonly syncService: ContributionSyncService,
    private readonly networkSyncService: NetworkSyncService,
    private readonly configService: ConfigService,
  ) {}

  async onModuleInit() {
    const kafkaBrokers = this.configService.get<string>('KAFKA_BROKERS', 'localhost:9092');
    const topic = this.configService.get<string>('CDC_TOPIC_CONTRIBUTION_OUTBOX', 'cdc.contribution.outbox');

    const kafka = new Kafka({
      clientId: 'mining-service',
      brokers: kafkaBrokers.split(','),
    });

    this.consumer = kafka.consumer({ groupId: 'mining-service-contribution-sync' });

    try {
      await this.consumer.connect();
      await this.consumer.subscribe({ topic, fromBeginning: false });

      await this.consumer.run({
        eachMessage: async (payload: EachMessagePayload) => {
          await this.handleMessage(payload);
        },
      });

      this.logger.log(`Subscribed to ${topic} for contribution sync`);
    } catch (error) {
      this.logger.error('Failed to connect to Kafka for contribution sync', error);
    }
  }

  private async handleMessage(payload: EachMessagePayload): Promise<void> {
    try {
      const { message } = payload;
      if (!message.value) return;

      const event = JSON.parse(message.value.toString());

      // CDC 消息格式：{ after: { event_type, payload, ... } }
      const data = event.after || event;
      const eventType = data.event_type || data.eventType;
      const eventPayload = typeof data.payload === 'string' ? JSON.parse(data.payload) : data.payload;

      if (!eventPayload) return;

      if (eventType === 'ContributionAccountUpdated') {
        this.logger.debug(`Received ContributionAccountUpdated for ${eventPayload.accountSequence}`);

        // 使用 effectiveContribution 作为挖矿算力
        await this.syncService.handleContributionCalculated({
          accountSequence: eventPayload.accountSequence,
          personalContribution: eventPayload.effectiveContribution || eventPayload.totalContribution || '0',
          calculatedAt: eventPayload.createdAt || new Date().toISOString(),
        });
      } else if (eventType === 'DailySnapshotCreated') {
        this.logger.log(`Received DailySnapshotCreated for ${eventPayload.snapshotDate}`);

        await this.syncService.handleDailySnapshotCreated({
          snapshotId: eventPayload.snapshotId,
          snapshotDate: eventPayload.snapshotDate,
          totalContribution: eventPayload.totalContribution,
          activeAccounts: eventPayload.activeAccounts,
        });
      } else if (eventType === 'SystemAccountSynced') {
        this.logger.log(`Received SystemAccountSynced for ${eventPayload.accountType}`);

        await this.networkSyncService.handleSystemAccountSynced({
          accountType: eventPayload.accountType,
          name: eventPayload.name,
          contributionBalance: eventPayload.contributionBalance,
        });
      } else if (eventType === 'NetworkProgressUpdated') {
        this.logger.log(`Received NetworkProgressUpdated: trees=${eventPayload.totalTreeCount}`);

        await this.networkSyncService.handleNetworkProgressUpdated({
          totalTreeCount: eventPayload.totalTreeCount,
          totalAdoptionOrders: eventPayload.totalAdoptionOrders,
          totalAdoptedUsers: eventPayload.totalAdoptedUsers,
          currentUnit: eventPayload.currentUnit,
          currentMultiplier: eventPayload.currentMultiplier,
          currentContributionPerTree: eventPayload.currentContributionPerTree,
          nextUnitTreeCount: eventPayload.nextUnitTreeCount,
        });
      } else if (eventType === 'UnallocatedContributionSynced') {
        this.logger.log(`Received UnallocatedContributionSynced: adoption=${eventPayload.sourceAdoptionId}, type=${eventPayload.contributionType}`);

        await this.networkSyncService.handleUnallocatedContributionSynced({
          sourceAdoptionId: eventPayload.sourceAdoptionId,
          sourceAccountSequence: eventPayload.sourceAccountSequence,
          wouldBeAccountSequence: eventPayload.wouldBeAccountSequence,
          contributionType: eventPayload.contributionType,
          amount: eventPayload.amount,
          reason: eventPayload.reason,
          effectiveDate: eventPayload.effectiveDate,
          expireDate: eventPayload.expireDate,
        });
      }
    } catch (error) {
      this.logger.error('Failed to handle contribution event', error);
    }
  }
}
