import { Controller, Logger, OnModuleInit } from '@nestjs/common';
import { EventPattern, Payload } from '@nestjs/microservices';
import Decimal from 'decimal.js';
import { RedisService } from '../../redis/redis.service';
import { ProcessedEventRepository } from '../../persistence/repositories/processed-event.repository';
import { PoolAccountService } from '../../../application/services/pool-account.service';
import { PoolAccountType } from '@prisma/client';

// 4小时 TTL（秒）
const IDEMPOTENCY_TTL_SECONDS = 4 * 60 * 60;

// 池类型到 PoolAccountType 的映射
const POOL_TYPE_MAP: Record<string, PoolAccountType> = {
  'BURN_POOL': 'SHARE_POOL_A',
  'MINING_POOL': 'SHARE_POOL_B',
};

interface PoolAccountDepositConfirmedPayload {
  depositId: string;
  chainType: string;
  txHash: string;
  fromAddress: string;
  toAddress: string;
  poolType: 'BURN_POOL' | 'MINING_POOL';
  tokenContract: string;
  amount: string;
  amountFormatted: string;
  confirmations: number;
  blockNumber: string;
  blockTimestamp: string;
}

/**
 * 池账户充值事件消费者
 * 监听 mining-blockchain-service 发布的池账户充值确认事件
 */
@Controller()
export class PoolAccountDepositConsumer implements OnModuleInit {
  private readonly logger = new Logger(PoolAccountDepositConsumer.name);

  constructor(
    private readonly redis: RedisService,
    private readonly processedEventRepo: ProcessedEventRepository,
    private readonly poolAccountService: PoolAccountService,
  ) {}

  async onModuleInit() {
    this.logger.log('PoolAccountDepositConsumer initialized');
  }

  /**
   * 处理池账户充值确认事件
   * Topic: mining_blockchain.pool_account.deposits
   */
  @EventPattern('mining_blockchain.pool_account.deposits')
  async handlePoolAccountDeposit(@Payload() message: any): Promise<void> {
    const eventData = message.value || message;
    const eventId = eventData.eventId || message.eventId;

    if (!eventId) {
      this.logger.warn('Received pool deposit event without eventId, skipping');
      return;
    }

    await this.processDeposit(eventId, eventData.payload || eventData);
  }

  /**
   * 处理充值入账
   */
  private async processDeposit(
    eventId: string,
    payload: PoolAccountDepositConfirmedPayload,
  ): Promise<void> {
    this.logger.debug(`Processing pool deposit event: ${eventId}`);

    // 幂等性检查
    if (await this.isEventProcessed(eventId)) {
      this.logger.debug(`Event ${eventId} already processed, skipping`);
      return;
    }

    try {
      const amount = new Decimal(payload.amountFormatted);

      if (amount.isZero() || amount.isNegative()) {
        this.logger.warn(`Invalid deposit amount: ${payload.amountFormatted}, skipping`);
        return;
      }

      // 映射池类型
      const poolType = POOL_TYPE_MAP[payload.poolType];
      if (!poolType) {
        this.logger.error(`Unknown pool type: ${payload.poolType}, skipping`);
        return;
      }

      // 调用 pool account service 进行入账
      await this.poolAccountService.blockchainDeposit(poolType, amount, {
        txHash: payload.txHash,
        fromAddress: payload.fromAddress,
        blockNumber: payload.blockNumber,
        depositId: payload.depositId,
      });

      // 标记为已处理
      await this.markEventProcessed(eventId, 'pool_account.deposit.confirmed');

      const poolName = payload.poolType === 'BURN_POOL' ? '100亿销毁池' : '200万挖矿池';
      this.logger.log(
        `Pool deposit processed: ${amount.toFixed(8)} fUSDT to ${poolName} (tx: ${payload.txHash.slice(0, 10)}...)`,
      );
    } catch (error) {
      this.logger.error(
        `Failed to process pool deposit event ${eventId}`,
        error instanceof Error ? error.stack : error,
      );
      throw error; // 让 Kafka 重试
    }
  }

  /**
   * 幂等性检查 - Redis + DB 双重检查
   */
  private async isEventProcessed(eventId: string): Promise<boolean> {
    const redisKey = `processed-event:pool-deposit:${eventId}`;

    const cached = await this.redis.get(redisKey);
    if (cached) return true;

    const dbRecord = await this.processedEventRepo.findByEventId(eventId);
    if (dbRecord) {
      await this.redis.set(redisKey, '1', IDEMPOTENCY_TTL_SECONDS);
      return true;
    }

    return false;
  }

  /**
   * 标记事件为已处理
   */
  private async markEventProcessed(
    eventId: string,
    eventType: string,
  ): Promise<void> {
    await this.processedEventRepo.create({
      eventId,
      eventType,
      sourceService: 'mining-blockchain-service',
    });

    const redisKey = `processed-event:pool-deposit:${eventId}`;
    await this.redis.set(redisKey, '1', IDEMPOTENCY_TTL_SECONDS);
  }
}
