/**
 * Deposit Confirmed Event Handler
 *
 * Handles deposit confirmation events from blockchain-service.
 * Credits user wallets when deposits are confirmed on-chain.
 */

import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { WalletApplicationService } from '@/application/services/wallet-application.service';
import { HandleDepositCommand } from '@/application/commands';
import {
  DepositEventConsumerService,
  DepositConfirmedPayload,
} from '@/infrastructure/kafka/deposit-event-consumer.service';
import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service';
import { ChainType } from '@/domain/value-objects';

@Injectable()
export class DepositConfirmedHandler implements OnModuleInit {
  private readonly logger = new Logger(DepositConfirmedHandler.name);

  constructor(
    private readonly depositEventConsumer: DepositEventConsumerService,
    private readonly walletApplicationService: WalletApplicationService,
    private readonly eventPublisher: EventPublisherService,
  ) {}

  onModuleInit() {
    this.depositEventConsumer.onDepositConfirmed(this.handleDepositConfirmed.bind(this));
    this.logger.log('DepositConfirmedHandler registered');
  }

  async handleDepositConfirmed(payload: DepositConfirmedPayload): Promise<void> {
    this.logger.log(`Processing deposit confirmation: txHash=${payload.txHash}`);

    try {
      // Map chainType string to ChainType enum
      const chainType = this.mapChainType(payload.chainType);

      const command: HandleDepositCommand = {
        accountSequence: payload.accountSequence,
        userId: payload.userId,
        amount: parseFloat(payload.amountFormatted),
        chainType,
        txHash: payload.txHash,
      };

      await this.walletApplicationService.handleDeposit(command);

      this.logger.log(
        `Deposit credited successfully: ` +
        `txHash=${payload.txHash}, ` +
        `amount=${payload.amountFormatted} USDT, ` +
        `userId=${payload.userId}, ` +
        `accountSequence=${payload.accountSequence}`,
      );

      // 发送 ACK 确认事件给 blockchain-service
      await this.sendDepositCreditedAck(payload);
    } catch (error) {
      // Check if it's a duplicate transaction error (already processed)
      if (error.message?.includes('Duplicate transaction')) {
        this.logger.warn(
          `Deposit already processed (duplicate): txHash=${payload.txHash}`,
        );
        // 重复交易也发送 ACK，确保 blockchain-service 知道已处理
        await this.sendDepositCreditedAck(payload);
        return;
      }

      this.logger.error(
        `Failed to process deposit: txHash=${payload.txHash}`,
        error,
      );
      throw error;
    }
  }

  /**
   * 发送充值入账确认事件给 blockchain-service
   * 这是 Outbox Pattern 的 ACK 机制，确保 blockchain-service 知道事件已被成功处理
   */
  private async sendDepositCreditedAck(payload: DepositConfirmedPayload): Promise<void> {
    try {
      await this.eventPublisher.publish({
        eventType: 'wallet.deposit.credited',
        payload: {
          depositId: payload.depositId,
          txHash: payload.txHash,
          userId: payload.userId,
          accountSequence: payload.accountSequence,
          amount: payload.amountFormatted,
          creditedAt: new Date().toISOString(),
        },
      });

      this.logger.log(
        `[ACK] Sent deposit credited ACK: depositId=${payload.depositId}, txHash=${payload.txHash}`,
      );
    } catch (error) {
      // ACK 发送失败不应该影响主流程，只记录警告
      // blockchain-service 的 outbox 机制会处理重试
      this.logger.warn(
        `[ACK] Failed to send deposit credited ACK: depositId=${payload.depositId}`,
        error,
      );
    }
  }

  private mapChainType(chainType: string): ChainType {
    const normalized = chainType.toUpperCase();
    switch (normalized) {
      case 'KAVA':
        return ChainType.KAVA;
      case 'BSC':
        return ChainType.BSC;
      default:
        this.logger.warn(`Unknown chain type: ${chainType}, defaulting to KAVA`);
        return ChainType.KAVA;
    }
  }
}
