import { Injectable, Logger } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { ServiceEvent } from './cdc-consumer.service';

/** Prisma 事务客户端类型 */
type TransactionClient = Prisma.TransactionClient;

/**
 * mining-wallet-service CDC 事件处理器
 * 所有 handler 都接受事务客户端参数，支持事务性幂等消费
 */
@Injectable()
export class WalletSyncHandlers {
  private readonly logger = new Logger(WalletSyncHandlers.name);

  // ===========================================================================
  // 区域数据处理
  // ===========================================================================

  async handleProvinceCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedProvince.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        code: payload.code,
        name: payload.name,
        status: payload.status || 'ACTIVE',
      },
      update: {
        code: payload.code,
        name: payload.name,
        status: payload.status || 'ACTIVE',
      },
    });

    this.logger.debug(`Synced province: ${payload.code}`);
  }

  async handleProvinceUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedProvince.updateMany({
      where: { originalId: payload.id },
      data: {
        code: payload.code,
        name: payload.name,
        status: payload.status,
      },
    });

    this.logger.debug(`Updated province: ${payload.code}`);
  }

  async handleCityCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedCity.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        provinceId: payload.provinceId,
        code: payload.code,
        name: payload.name,
        status: payload.status || 'ACTIVE',
      },
      update: {
        provinceId: payload.provinceId,
        code: payload.code,
        name: payload.name,
        status: payload.status || 'ACTIVE',
      },
    });

    this.logger.debug(`Synced city: ${payload.code}`);
  }

  async handleCityUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedCity.updateMany({
      where: { originalId: payload.id },
      data: {
        provinceId: payload.provinceId,
        code: payload.code,
        name: payload.name,
        status: payload.status,
      },
    });

    this.logger.debug(`Updated city: ${payload.code}`);
  }

  async handleUserRegionMappingCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedUserRegionMapping.upsert({
      where: { accountSequence: payload.accountSequence },
      create: {
        accountSequence: payload.accountSequence,
        cityId: payload.cityId,
        assignedAt: new Date(payload.assignedAt),
        assignedBy: payload.assignedBy,
      },
      update: {
        cityId: payload.cityId,
        assignedAt: new Date(payload.assignedAt),
        assignedBy: payload.assignedBy,
      },
    });

    this.logger.debug(`Synced user region mapping: ${payload.accountSequence}`);
  }

  async handleUserRegionMappingUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedUserRegionMapping.updateMany({
      where: { accountSequence: payload.accountSequence },
      data: {
        cityId: payload.cityId,
        assignedAt: new Date(payload.assignedAt),
        assignedBy: payload.assignedBy,
      },
    });

    this.logger.debug(`Updated user region mapping: ${payload.accountSequence}`);
  }

  // ===========================================================================
  // 系统账户处理
  // ===========================================================================

  async handleWalletSystemAccountCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedWalletSystemAccount.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        accountType: payload.accountType,
        name: payload.name,
        code: payload.code,
        provinceId: payload.provinceId,
        cityId: payload.cityId,
        shareBalance: payload.shareBalance || 0,
        usdtBalance: payload.usdtBalance || 0,
        greenPointBalance: payload.greenPointBalance || 0,
        frozenShare: payload.frozenShare || 0,
        frozenUsdt: payload.frozenUsdt || 0,
        totalInflow: payload.totalInflow || 0,
        totalOutflow: payload.totalOutflow || 0,
        blockchainAddress: payload.blockchainAddress,
        isActive: payload.isActive ?? true,
      },
      update: {
        accountType: payload.accountType,
        name: payload.name,
        code: payload.code,
        provinceId: payload.provinceId,
        cityId: payload.cityId,
        shareBalance: payload.shareBalance,
        usdtBalance: payload.usdtBalance,
        greenPointBalance: payload.greenPointBalance,
        frozenShare: payload.frozenShare,
        frozenUsdt: payload.frozenUsdt,
        totalInflow: payload.totalInflow,
        totalOutflow: payload.totalOutflow,
        blockchainAddress: payload.blockchainAddress,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Synced wallet system account: ${payload.code}`);
  }

  async handleWalletSystemAccountUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedWalletSystemAccount.updateMany({
      where: { originalId: payload.id },
      data: {
        name: payload.name,
        shareBalance: payload.shareBalance,
        usdtBalance: payload.usdtBalance,
        greenPointBalance: payload.greenPointBalance,
        frozenShare: payload.frozenShare,
        frozenUsdt: payload.frozenUsdt,
        totalInflow: payload.totalInflow,
        totalOutflow: payload.totalOutflow,
        blockchainAddress: payload.blockchainAddress,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Updated wallet system account: ${payload.code}`);
  }

  // ===========================================================================
  // 池账户处理
  // ===========================================================================

  async handleWalletPoolAccountCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedWalletPoolAccount.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        poolType: payload.poolType,
        name: payload.name,
        balance: payload.balance || 0,
        totalInflow: payload.totalInflow || 0,
        totalOutflow: payload.totalOutflow || 0,
        targetBurn: payload.targetBurn,
        remainingBurn: payload.remainingBurn,
        isActive: payload.isActive ?? true,
      },
      update: {
        name: payload.name,
        balance: payload.balance,
        totalInflow: payload.totalInflow,
        totalOutflow: payload.totalOutflow,
        targetBurn: payload.targetBurn,
        remainingBurn: payload.remainingBurn,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Synced wallet pool account: ${payload.poolType}`);
  }

  async handleWalletPoolAccountUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedWalletPoolAccount.updateMany({
      where: { originalId: payload.id },
      data: {
        name: payload.name,
        balance: payload.balance,
        totalInflow: payload.totalInflow,
        totalOutflow: payload.totalOutflow,
        targetBurn: payload.targetBurn,
        remainingBurn: payload.remainingBurn,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Updated wallet pool account: ${payload.poolType}`);
  }

  // ===========================================================================
  // 用户钱包处理
  // ===========================================================================

  async handleUserWalletCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedUserWallet.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        accountSequence: payload.accountSequence,
        walletType: payload.walletType,
        balance: payload.balance || 0,
        frozenBalance: payload.frozenBalance || 0,
        totalInflow: payload.totalInflow || 0,
        totalOutflow: payload.totalOutflow || 0,
        isActive: payload.isActive ?? true,
      },
      update: {
        balance: payload.balance,
        frozenBalance: payload.frozenBalance,
        totalInflow: payload.totalInflow,
        totalOutflow: payload.totalOutflow,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Synced user wallet: ${payload.accountSequence}/${payload.walletType}`);
  }

  async handleUserWalletUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedUserWallet.updateMany({
      where: { originalId: payload.id },
      data: {
        balance: payload.balance,
        frozenBalance: payload.frozenBalance,
        totalInflow: payload.totalInflow,
        totalOutflow: payload.totalOutflow,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Updated user wallet: ${payload.accountSequence}/${payload.walletType}`);
  }

  // ===========================================================================
  // 提现请求处理
  // ===========================================================================

  async handleWithdrawRequestCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedWithdrawRequest.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        requestNo: payload.requestNo,
        accountSequence: payload.accountSequence,
        assetType: payload.assetType,
        amount: payload.amount,
        fee: payload.fee || 0,
        netAmount: payload.netAmount,
        toAddress: payload.toAddress,
        status: payload.status,
        txHash: payload.txHash,
        blockNumber: payload.blockNumber,
        confirmations: payload.confirmations || 0,
        errorMessage: payload.errorMessage,
        approvedBy: payload.approvedBy,
        approvedAt: payload.approvedAt ? new Date(payload.approvedAt) : null,
        createdAt: new Date(payload.createdAt),
        completedAt: payload.completedAt ? new Date(payload.completedAt) : null,
      },
      update: {
        status: payload.status,
        txHash: payload.txHash,
        blockNumber: payload.blockNumber,
        confirmations: payload.confirmations,
        errorMessage: payload.errorMessage,
        approvedBy: payload.approvedBy,
        approvedAt: payload.approvedAt ? new Date(payload.approvedAt) : null,
        completedAt: payload.completedAt ? new Date(payload.completedAt) : null,
      },
    });

    this.logger.debug(`Synced withdraw request: ${payload.requestNo}`);
  }

  async handleWithdrawRequestUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedWithdrawRequest.updateMany({
      where: { originalId: payload.id },
      data: {
        status: payload.status,
        txHash: payload.txHash,
        blockNumber: payload.blockNumber,
        confirmations: payload.confirmations,
        errorMessage: payload.errorMessage,
        approvedBy: payload.approvedBy,
        approvedAt: payload.approvedAt ? new Date(payload.approvedAt) : null,
        completedAt: payload.completedAt ? new Date(payload.completedAt) : null,
      },
    });

    this.logger.debug(`Updated withdraw request: ${payload.requestNo}`);
  }

  // ===========================================================================
  // 充值记录处理
  // ===========================================================================

  async handleDepositRecordCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedDepositRecord.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        txHash: payload.txHash,
        fromAddress: payload.fromAddress,
        toAddress: payload.toAddress,
        assetType: payload.assetType,
        amount: payload.amount,
        blockNumber: payload.blockNumber,
        confirmations: payload.confirmations || 0,
        matchedAccountSeq: payload.matchedAccountSeq,
        isProcessed: payload.isProcessed || false,
        processedAt: payload.processedAt ? new Date(payload.processedAt) : null,
        createdAt: new Date(payload.createdAt),
      },
      update: {
        confirmations: payload.confirmations,
        matchedAccountSeq: payload.matchedAccountSeq,
        isProcessed: payload.isProcessed,
        processedAt: payload.processedAt ? new Date(payload.processedAt) : null,
      },
    });

    this.logger.debug(`Synced deposit record: ${payload.txHash}`);
  }

  async handleDepositRecordUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedDepositRecord.updateMany({
      where: { originalId: payload.id },
      data: {
        confirmations: payload.confirmations,
        matchedAccountSeq: payload.matchedAccountSeq,
        isProcessed: payload.isProcessed,
        processedAt: payload.processedAt ? new Date(payload.processedAt) : null,
      },
    });

    this.logger.debug(`Updated deposit record: ${payload.txHash}`);
  }

  // ===========================================================================
  // DEX Swap 处理
  // ===========================================================================

  async handleDexSwapRecordCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedDexSwapRecord.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        swapNo: payload.swapNo,
        accountSequence: payload.accountSequence,
        fromAsset: payload.fromAsset,
        toAsset: payload.toAsset,
        fromAmount: payload.fromAmount,
        toAmount: payload.toAmount,
        exchangeRate: payload.exchangeRate,
        slippage: payload.slippage || 0,
        fee: payload.fee || 0,
        status: payload.status,
        txHash: payload.txHash,
        blockNumber: payload.blockNumber,
        errorMessage: payload.errorMessage,
        createdAt: new Date(payload.createdAt),
        completedAt: payload.completedAt ? new Date(payload.completedAt) : null,
      },
      update: {
        toAmount: payload.toAmount,
        exchangeRate: payload.exchangeRate,
        status: payload.status,
        txHash: payload.txHash,
        blockNumber: payload.blockNumber,
        errorMessage: payload.errorMessage,
        completedAt: payload.completedAt ? new Date(payload.completedAt) : null,
      },
    });

    this.logger.debug(`Synced dex swap record: ${payload.swapNo}`);
  }

  async handleDexSwapRecordUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedDexSwapRecord.updateMany({
      where: { originalId: payload.id },
      data: {
        toAmount: payload.toAmount,
        exchangeRate: payload.exchangeRate,
        status: payload.status,
        txHash: payload.txHash,
        blockNumber: payload.blockNumber,
        errorMessage: payload.errorMessage,
        completedAt: payload.completedAt ? new Date(payload.completedAt) : null,
      },
    });

    this.logger.debug(`Updated dex swap record: ${payload.swapNo}`);
  }

  // ===========================================================================
  // 地址绑定处理
  // ===========================================================================

  async handleBlockchainAddressBindingCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedBlockchainAddressBinding.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        accountSequence: payload.accountSequence,
        kavaAddress: payload.kavaAddress,
        isVerified: payload.isVerified || false,
        verifiedAt: payload.verifiedAt ? new Date(payload.verifiedAt) : null,
        verificationTxHash: payload.verificationTxHash,
        createdAt: new Date(payload.createdAt),
      },
      update: {
        kavaAddress: payload.kavaAddress,
        isVerified: payload.isVerified,
        verifiedAt: payload.verifiedAt ? new Date(payload.verifiedAt) : null,
        verificationTxHash: payload.verificationTxHash,
      },
    });

    this.logger.debug(`Synced blockchain address binding: ${payload.accountSequence}`);
  }

  async handleBlockchainAddressBindingUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedBlockchainAddressBinding.updateMany({
      where: { originalId: payload.id },
      data: {
        kavaAddress: payload.kavaAddress,
        isVerified: payload.isVerified,
        verifiedAt: payload.verifiedAt ? new Date(payload.verifiedAt) : null,
        verificationTxHash: payload.verificationTxHash,
      },
    });

    this.logger.debug(`Updated blockchain address binding: ${payload.accountSequence}`);
  }

  // ===========================================================================
  // 黑洞合约处理
  // ===========================================================================

  async handleBlackHoleContractCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedBlackHoleContract.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        contractAddress: payload.contractAddress,
        name: payload.name,
        totalBurned: payload.totalBurned || 0,
        targetBurn: payload.targetBurn,
        remainingBurn: payload.remainingBurn,
        isActive: payload.isActive ?? true,
      },
      update: {
        name: payload.name,
        totalBurned: payload.totalBurned,
        targetBurn: payload.targetBurn,
        remainingBurn: payload.remainingBurn,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Synced black hole contract: ${payload.contractAddress}`);
  }

  async handleBlackHoleContractUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedBlackHoleContract.updateMany({
      where: { originalId: payload.id },
      data: {
        name: payload.name,
        totalBurned: payload.totalBurned,
        targetBurn: payload.targetBurn,
        remainingBurn: payload.remainingBurn,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Updated black hole contract: ${payload.contractAddress}`);
  }

  // ===========================================================================
  // 销毁记录处理
  // ===========================================================================

  async handleBurnToBlackHoleRecordCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedBurnToBlackHoleRecord.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        blackHoleId: payload.blackHoleId,
        amount: payload.amount,
        sourceType: payload.sourceType,
        sourceAccountSeq: payload.sourceAccountSeq,
        sourceUserId: payload.sourceUserId,
        sourcePoolType: payload.sourcePoolType,
        txHash: payload.txHash,
        blockNumber: payload.blockNumber,
        memo: payload.memo,
        createdAt: new Date(payload.createdAt),
      },
      update: {
        txHash: payload.txHash,
        blockNumber: payload.blockNumber,
      },
    });

    this.logger.debug(`Synced burn to black hole record: ${payload.id}`);
  }

  // ===========================================================================
  // 费率配置处理
  // ===========================================================================

  async handleFeeConfigCreated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedFeeConfig.upsert({
      where: { originalId: payload.id },
      create: {
        originalId: payload.id,
        feeType: payload.feeType,
        feeRate: payload.feeRate,
        minFee: payload.minFee,
        maxFee: payload.maxFee,
        headquartersRate: payload.headquartersRate,
        operationRate: payload.operationRate,
        provinceRate: payload.provinceRate,
        cityRate: payload.cityRate,
        isActive: payload.isActive ?? true,
      },
      update: {
        feeRate: payload.feeRate,
        minFee: payload.minFee,
        maxFee: payload.maxFee,
        headquartersRate: payload.headquartersRate,
        operationRate: payload.operationRate,
        provinceRate: payload.provinceRate,
        cityRate: payload.cityRate,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Synced fee config: ${payload.feeType}`);
  }

  async handleFeeConfigUpdated(event: ServiceEvent, tx: TransactionClient): Promise<void> {
    const { payload } = event;

    await tx.syncedFeeConfig.updateMany({
      where: { originalId: payload.id },
      data: {
        feeRate: payload.feeRate,
        minFee: payload.minFee,
        maxFee: payload.maxFee,
        headquartersRate: payload.headquartersRate,
        operationRate: payload.operationRate,
        provinceRate: payload.provinceRate,
        cityRate: payload.cityRate,
        isActive: payload.isActive,
      },
    });

    this.logger.debug(`Updated fee config: ${payload.feeType}`);
  }
}
