import { Injectable, Logger, Inject, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Cron, CronExpression } from '@nestjs/schedule';
import { EvmProviderAdapter, TransferEvent } from '@/infrastructure/blockchain/evm-provider.adapter';
import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service';
import { ConfirmationPolicyService } from '@/domain/services/confirmation-policy.service';
import { ChainConfigService } from '@/domain/services/chain-config.service';
import {
  MARKET_MAKER_DEPOSIT_REPOSITORY,
  IMarketMakerDepositRepository,
  MarketMakerDepositDto,
  MARKET_MAKER_CHECKPOINT_REPOSITORY,
  IMarketMakerCheckpointRepository,
} from '@/domain/repositories/market-maker-deposit.repository.interface';
import {
  OUTBOX_EVENT_REPOSITORY,
  IOutboxEventRepository,
} from '@/domain/repositories/outbox-event.repository.interface';
import { ChainType, BlockNumber } from '@/domain/value-objects';
import { ChainTypeEnum, MarketMakerAssetType, MarketMakerDepositStatus } from '@/domain/enums';
import { MarketMakerDepositConfirmedEvent } from '@/domain/events';

interface TokenConfig {
  assetType: MarketMakerAssetType;
  contract: string;
  walletAddress: string;
  name: string;
}

/**
 * 做市商充值检测服务
 *
 * 负责扫描区块链、检测做市商钱包的 eUSDT/fUSDT 充值、更新确认状态
 * 当充值达到确认数后，通过 Kafka 通知 trading-service 进行入账
 */
@Injectable()
export class MarketMakerDepositDetectionService implements OnModuleInit {
  private readonly logger = new Logger(MarketMakerDepositDetectionService.name);
  private readonly scanBatchSize: number;
  private readonly tokenConfigs: TokenConfig[];
  private isEnabled: boolean = false;

  constructor(
    private readonly configService: ConfigService,
    private readonly evmProvider: EvmProviderAdapter,
    private readonly eventPublisher: EventPublisherService,
    private readonly confirmationPolicy: ConfirmationPolicyService,
    private readonly chainConfig: ChainConfigService,
    @Inject(MARKET_MAKER_DEPOSIT_REPOSITORY)
    private readonly depositRepo: IMarketMakerDepositRepository,
    @Inject(MARKET_MAKER_CHECKPOINT_REPOSITORY)
    private readonly checkpointRepo: IMarketMakerCheckpointRepository,
    @Inject(OUTBOX_EVENT_REPOSITORY)
    private readonly outboxRepo: IOutboxEventRepository,
  ) {
    this.scanBatchSize = this.configService.get<number>('blockchain.scanBatchSize', 100);

    // 配置代币信息和对应的做市商钱包
    const eUsdtContract = this.configService.get<string>('blockchain.kava.eUsdtContract', '');
    const fUsdtContract = this.configService.get<string>('blockchain.kava.fUsdtContract', '');
    const eusdtMarketMakerAddress = this.configService.get<string>('blockchain.eusdtMarketMaker.walletAddress', '');
    const fusdtMarketMakerAddress = this.configService.get<string>('blockchain.fusdtMarketMaker.walletAddress', '');

    this.tokenConfigs = [
      {
        assetType: MarketMakerAssetType.EUSDT,
        contract: eUsdtContract,
        walletAddress: eusdtMarketMakerAddress,
        name: '积分股 (eUSDT)',
      },
      {
        assetType: MarketMakerAssetType.FUSDT,
        contract: fUsdtContract,
        walletAddress: fusdtMarketMakerAddress,
        name: '积分值 (fUSDT)',
      },
    ];
  }

  async onModuleInit() {
    // 验证配置：检查每种代币的做市商钱包地址
    const validConfigs = this.tokenConfigs.filter((t) => t.contract && t.walletAddress);

    if (validConfigs.length === 0) {
      this.logger.warn(
        '[INIT] 没有有效的做市商钱包配置，做市商充值监控功能已禁用',
      );
      this.isEnabled = false;
      return;
    }

    // 验证代币合约和钱包配置
    this.tokenConfigs.forEach((t) => {
      if (!t.walletAddress) {
        this.logger.warn(`[INIT] ${t.name} 做市商钱包地址未配置，该代币充值监控已禁用`);
      }
      if (!t.contract) {
        this.logger.warn(`[INIT] ${t.name} 代币合约未配置`);
      }
    });

    this.isEnabled = true;
    this.logger.log(`[INIT] MarketMakerDepositDetectionService initialized`);
    this.tokenConfigs.forEach((t) => {
      if (t.contract && t.walletAddress) {
        this.logger.log(`[INIT] ${t.name}: 合约=${t.contract}, 钱包=${t.walletAddress}`);
      }
    });
  }

  /**
   * 定时扫描区块（每5秒）
   */
  @Cron(CronExpression.EVERY_5_SECONDS)
  async scanBlocks(): Promise<void> {
    if (!this.isEnabled) return;

    const chainType = ChainType.fromEnum(ChainTypeEnum.KAVA);

    // 扫描每种代币
    for (const tokenConfig of this.tokenConfigs) {
      // 跳过没有合约或钱包地址的代币
      if (!tokenConfig.contract || !tokenConfig.walletAddress) continue;

      try {
        await this.scanTokenDeposits(chainType, tokenConfig);
      } catch (error) {
        this.logger.error(`Error scanning ${tokenConfig.name} deposits:`, error);
        await this.checkpointRepo.recordError(
          chainType,
          tokenConfig.assetType,
          error instanceof Error ? error.message : 'Unknown error',
        );
      }
    }
  }

  /**
   * 扫描单种代币的充值
   */
  private async scanTokenDeposits(chainType: ChainType, tokenConfig: TokenConfig): Promise<void> {
    // 获取上次扫描位置
    let lastBlock = await this.checkpointRepo.getLastScannedBlock(chainType, tokenConfig.assetType);

    if (!lastBlock) {
      // 首次扫描，从当前区块开始
      const currentBlock = await this.evmProvider.getCurrentBlockNumber(chainType);
      lastBlock = currentBlock.subtract(10); // 从10个块前开始
      await this.checkpointRepo.initializeIfNotExists(chainType, tokenConfig.assetType, lastBlock);
    }

    // 获取当前区块
    const currentBlock = await this.evmProvider.getCurrentBlockNumber(chainType);

    // 计算扫描范围
    const fromBlock = lastBlock.add(1);
    let toBlock = fromBlock.add(this.scanBatchSize - 1);

    // 不超过当前区块
    if (toBlock.isGreaterThan(currentBlock)) {
      toBlock = currentBlock;
    }

    // 如果没有新区块，跳过
    if (fromBlock.isGreaterThan(currentBlock)) {
      return;
    }

    this.logger.debug(
      `Scanning ${tokenConfig.name}: blocks ${fromBlock} to ${toBlock}`,
    );

    // 扫描 Transfer 事件
    const events = await this.evmProvider.scanTransferEvents(
      chainType,
      fromBlock,
      toBlock,
      tokenConfig.contract,
    );

    // 过滤出充值到对应做市商钱包的交易
    const deposits = events.filter(
      (e) => e.to.toLowerCase() === tokenConfig.walletAddress.toLowerCase(),
    );

    // 处理充值
    for (const deposit of deposits) {
      await this.processDeposit(chainType, tokenConfig, deposit);
    }

    // 更新检查点
    if (toBlock.isGreaterThan(lastBlock)) {
      await this.checkpointRepo.updateCheckpoint(chainType, tokenConfig.assetType, toBlock);
    }
  }

  /**
   * 处理检测到的充值
   */
  private async processDeposit(
    chainType: ChainType,
    tokenConfig: TokenConfig,
    event: TransferEvent,
  ): Promise<void> {
    // 检查是否已处理
    if (await this.depositRepo.existsByTxHash(event.txHash)) {
      this.logger.debug(`Market maker deposit already processed: ${event.txHash}`);
      return;
    }

    // 获取代币的 decimals
    const tokenDecimals = await this.evmProvider.getTokenDecimals(
      chainType,
      tokenConfig.contract,
    );

    // 格式化金额
    const divisor = BigInt(10 ** tokenDecimals);
    const integerPart = event.value / divisor;
    const fractionalPart = event.value % divisor;
    const amountFormatted = `${integerPart}.${fractionalPart.toString().padStart(tokenDecimals, '0')}`;

    // 创建充值记录
    const deposit: MarketMakerDepositDto = {
      chainType: chainType.toString(),
      txHash: event.txHash,
      fromAddress: event.from,
      toAddress: event.to,
      assetType: tokenConfig.assetType,
      tokenContract: tokenConfig.contract,
      amount: event.value,
      amountFormatted,
      blockNumber: event.blockNumber,
      blockTimestamp: event.blockTimestamp,
      logIndex: event.logIndex,
      confirmations: 0,
      status: MarketMakerDepositStatus.DETECTED,
      notifyAttempts: 0,
    };

    // 保存
    await this.depositRepo.save(deposit);

    this.logger.log(
      `[DEPOSIT] ${tokenConfig.name} deposit detected: ${event.txHash.slice(0, 10)}... -> ${tokenConfig.walletAddress.slice(0, 10)}... (${amountFormatted})`,
    );
  }

  /**
   * 定时更新确认状态（每30秒）
   */
  @Cron(CronExpression.EVERY_30_SECONDS)
  async updateConfirmations(): Promise<void> {
    if (!this.isEnabled) return;

    const chainType = ChainType.fromEnum(ChainTypeEnum.KAVA);

    try {
      await this.updateChainConfirmations(chainType);
    } catch (error) {
      this.logger.error(`Error updating market maker confirmations:`, error);
    }
  }

  /**
   * 更新确认状态
   */
  private async updateChainConfirmations(chainType: ChainType): Promise<void> {
    const pendingDeposits = await this.depositRepo.findPendingConfirmation(chainType);
    if (pendingDeposits.length === 0) return;

    const currentBlock = await this.evmProvider.getCurrentBlockNumber(chainType);
    const requiredConfirmations = this.confirmationPolicy.getRequiredConfirmations(chainType);

    for (const deposit of pendingDeposits) {
      const confirmations = Number(currentBlock.value - deposit.blockNumber);
      const isConfirmed = confirmations >= requiredConfirmations;

      // 更新状态
      const newStatus = isConfirmed
        ? MarketMakerDepositStatus.CONFIRMED
        : MarketMakerDepositStatus.CONFIRMING;

      await this.depositRepo.updateConfirmations(deposit.id!, confirmations, newStatus);

      // 如果已确认，创建事件
      if (isConfirmed && deposit.status !== MarketMakerDepositStatus.CONFIRMED) {
        const event = new MarketMakerDepositConfirmedEvent({
          depositId: deposit.id!.toString(),
          chainType: deposit.chainType,
          txHash: deposit.txHash,
          fromAddress: deposit.fromAddress,
          toAddress: deposit.toAddress,
          assetType: deposit.assetType,
          tokenContract: deposit.tokenContract,
          amount: deposit.amount.toString(),
          amountFormatted: deposit.amountFormatted,
          confirmations,
          blockNumber: deposit.blockNumber.toString(),
          blockTimestamp: deposit.blockTimestamp.toISOString(),
        });

        // 写入 outbox，保证可靠投递
        await this.outboxRepo.create({
          eventType: event.eventType,
          aggregateId: deposit.id!.toString(),
          aggregateType: 'MarketMakerDeposit',
          payload: event.toPayload(),
        });

        this.logger.log(
          `[CONFIRMED] Market maker deposit confirmed: ${deposit.txHash.slice(0, 10)}... (${confirmations} confirmations, ${deposit.assetType})`,
        );
      }
    }
  }
}
