import { Injectable, Logger } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import Decimal from 'decimal.js';
import { PrePlantingCdcEvent } from '../../infrastructure/kafka/pre-planting-cdc-consumer.service';
import { PrePlantingPrismaService } from '../../infrastructure/prisma/pre-planting-prisma.service';
import { PrePlantingContributionService } from '../services/pre-planting-contribution.service';
import { ContributionRateService } from '@/application/services/contribution-rate.service';
import { PRE_PLANTING_SOURCE_ID_OFFSET, PRE_PLANTING_PORTION_DIVISOR } from '../../domain/constants';

/**
 * 预种订单同步结果（用于事务提交后的算力计算）
 * 使用 orderNo（业务单号）作为关联键，避免依赖数据库自增 BigInt ID
 */
export interface PrePlantingOrderSyncResult {
  orderNo: string;
  needsCalculation: boolean;
}

/**
 * 预种订单 CDC 事件处理器
 *
 * [2026-02-17] 新增：处理 cdc.pre-planting.public.pre_planting_orders 的 CDC 事件
 *
 * === 处理逻辑 ===
 * 1. 同步预种订单到 pre_planting_synced_orders（追踪表）
 * 2. 当订单状态为 PAID 时，标记需要算力计算
 * 3. 在 synced_adoptions 中插入 marker 记录（用于 getDirectReferralAdoptedCount 正确计数）
 * 4. 事务提交后，触发 1/10 算力计算（PostCommitCallback）
 *
 * === 对现有系统的影响 ===
 * - 零修改现有代码
 * - synced_adoptions 中的 marker 记录设置 contributionDistributed=true，
 *   现有 processUndistributedAdoptions 调度器不会处理它
 * - marker 的 treeCount=0，即使被误处理也不会产生算力
 */
@Injectable()
export class PrePlantingOrderSyncedHandler {
  private readonly logger = new Logger(PrePlantingOrderSyncedHandler.name);

  constructor(
    private readonly prePlantingPrisma: PrePlantingPrismaService,
    private readonly contributionService: PrePlantingContributionService,
    private readonly contributionRateService: ContributionRateService,
  ) {}

  /**
   * 处理预种订单 CDC 事件（在主 PrismaService 事务内执行）
   *
   * @param event CDC 事件
   * @param tx 主 Prisma 事务客户端
   * @returns 同步结果（用于后置回调判断是否需要算力计算）
   */
  async handle(
    event: PrePlantingCdcEvent,
    tx: Prisma.TransactionClient,
  ): Promise<PrePlantingOrderSyncResult | null> {
    const { op, before, after } = event.payload;
    const data = after || before;

    if (!data) {
      this.logger.warn(`[PRE-PLANTING-ORDER] Empty data, op=${op}`);
      return null;
    }

    this.logger.log(
      `[PRE-PLANTING-ORDER] Event: op=${op}, id=${data.order_id ?? data.id}, status=${data.status}`,
    );

    switch (op) {
      case 'c': // create
      case 'r': // read (snapshot)
        return await this.handleCreateOrSnapshot(data, event, tx);
      case 'u': // update
        return await this.handleUpdate(data, before, event, tx);
      case 'd': // delete
        this.logger.warn(`[PRE-PLANTING-ORDER] Delete event: id=${data.id}`);
        return null;
      default:
        this.logger.warn(`[PRE-PLANTING-ORDER] Unknown op: ${op}`);
        return null;
    }
  }

  /**
   * 事务提交后的算力计算回调
   */
  async calculateAfterCommit(result: PrePlantingOrderSyncResult): Promise<void> {
    if (!result?.needsCalculation) return;

    this.logger.log(`[PRE-PLANTING-ORDER] Triggering contribution calculation: orderNo=${result.orderNo}`);
    try {
      await this.contributionService.calculateForPrePlantingOrder(result.orderNo);
      this.logger.log(`[PRE-PLANTING-ORDER] Contribution calculated: orderNo=${result.orderNo}`);
    } catch (error) {
      // 算力计算失败不影响数据同步，后续调度器会重试
      this.logger.error(
        `[PRE-PLANTING-ORDER] Contribution calculation failed: orderNo=${result.orderNo}`,
        error,
      );
    }
  }

  private async handleCreateOrSnapshot(
    data: any,
    event: PrePlantingCdcEvent,
    tx: Prisma.TransactionClient,
  ): Promise<PrePlantingOrderSyncResult | null> {
    const orderNo = data.order_no || data.orderNo;
    const accountSequence = data.account_sequence || data.accountSequence;
    const status = data.status;

    if (!orderNo || !accountSequence) {
      this.logger.warn(`[PRE-PLANTING-ORDER] Missing orderNo or accountSequence, data=${JSON.stringify(data)}`);
      return null;
    }

    // 获取当日贡献值
    const paidAt = data.paid_at || data.paidAt || data.created_at || data.createdAt;
    let contributionPerTree = new Decimal('22617');
    if (paidAt) {
      try {
        contributionPerTree = await this.contributionRateService.getContributionPerTree(new Date(paidAt));
      } catch (error) {
        this.logger.warn(`[PRE-PLANTING-ORDER] Failed to get rate, using default`, error);
      }
    }
    const contributionPerPortion = contributionPerTree.div(PRE_PLANTING_PORTION_DIVISOR);

    // 同步到预种追踪表（以 orderNo 为唯一键）
    await this.syncToTrackingTable(data, event, contributionPerPortion);

    // 当状态为 PAID 时，在 synced_adoptions 中插入 marker（用于 unlock 计数）
    const needsCalculation = status === 'PAID';
    if (needsCalculation) {
      await this.ensureAdoptionMarker(accountSequence, orderNo, paidAt, tx);
    }

    return { orderNo, needsCalculation };
  }

  private async handleUpdate(
    after: any,
    before: any,
    event: PrePlantingCdcEvent,
    tx: Prisma.TransactionClient,
  ): Promise<PrePlantingOrderSyncResult | null> {
    const orderNo = after.order_no || after.orderNo;
    const accountSequence = after.account_sequence || after.accountSequence;
    const newStatus = after.status;
    const oldStatus = before?.status;

    if (!orderNo || !accountSequence) {
      this.logger.warn(`[PRE-PLANTING-ORDER] Missing orderNo or accountSequence in update`);
      return null;
    }

    // 获取当日贡献值
    const paidAt = after.paid_at || after.paidAt || after.created_at || after.createdAt;
    let contributionPerTree = new Decimal('22617');
    if (paidAt) {
      try {
        contributionPerTree = await this.contributionRateService.getContributionPerTree(new Date(paidAt));
      } catch (error) {
        this.logger.warn(`[PRE-PLANTING-ORDER] Failed to get rate, using default`, error);
      }
    }
    const contributionPerPortion = contributionPerTree.div(PRE_PLANTING_PORTION_DIVISOR);

    // 同步到预种追踪表
    await this.syncToTrackingTable(after, event, contributionPerPortion);

    // 只在状态变为 PAID（且之前不是 PAID）时触发算力计算
    const statusChangedToPaid = newStatus === 'PAID' && oldStatus !== 'PAID';
    if (statusChangedToPaid) {
      await this.ensureAdoptionMarker(accountSequence, orderNo, paidAt, tx);
    }

    // 检查是否已分配
    const alreadyDistributed = await this.isAlreadyDistributed(orderNo);

    return {
      orderNo,
      needsCalculation: statusChangedToPaid && !alreadyDistributed,
    };
  }

  /**
   * 同步到预种追踪表（pre_planting_synced_orders）
   * 使用 orderNo（业务单号）作为 upsert 唯一键，不依赖 BigInt 自增 ID
   */
  private async syncToTrackingTable(
    data: any,
    event: PrePlantingCdcEvent,
    contributionPerPortion: Decimal,
  ): Promise<void> {
    try {
      const orderNo = data.order_no || data.orderNo || '';
      const originalOrderId = data.order_id ? BigInt(data.order_id) : BigInt(0);
      await this.prePlantingPrisma.prePlantingSyncedOrder.upsert({
        where: { orderNo },
        create: {
          originalOrderId,
          orderNo,
          userId: BigInt(data.user_id || data.userId || 0),
          accountSequence: data.account_sequence || data.accountSequence,
          portionCount: data.portion_count || data.portionCount || 1,
          pricePerPortion: data.price_per_portion || data.pricePerPortion || 3566,
          totalAmount: data.total_amount || data.totalAmount || 3566,
          provinceCode: data.province_code || data.provinceCode || '',
          cityCode: data.city_code || data.cityCode || '',
          status: data.status || 'CREATED',
          mergedToMergeId: data.merged_to_merge_id ? BigInt(data.merged_to_merge_id) : null,
          paidAt: data.paid_at ? new Date(data.paid_at) : null,
          createdAt: new Date(data.created_at || data.createdAt || new Date()),
          contributionPerPortion,
          sourceTopic: event.topic,
          sourceOffset: event.offset,
        },
        update: {
          orderNo: data.order_no || data.orderNo || '',
          status: data.status || 'CREATED',
          mergedToMergeId: data.merged_to_merge_id ? BigInt(data.merged_to_merge_id) : null,
          paidAt: data.paid_at ? new Date(data.paid_at) : null,
          contributionPerPortion,
          sourceTopic: event.topic,
          sourceOffset: event.offset,
          syncedAt: new Date(),
        },
      });
    } catch (error) {
      this.logger.error(`[PRE-PLANTING-ORDER] Failed to sync tracking table`, error);
      // 追踪表同步失败不影响主流程（最终一致性）
    }
  }

  /**
   * 在 synced_adoptions 中插入 marker 记录（每用户仅一条）
   *
   * 目的：让现有的 getDirectReferralAdoptedCount 能正确计入预种用户
   *
   * marker 特征：
   * - originalAdoptionId = 10,000,000,000 + prePlantingOrderId（避免与正常认种冲突）
   * - treeCount = 0（不产生算力，算力由 PrePlantingContributionService 处理）
   * - status = 'MINING_ENABLED'（让 getDirectReferralAdoptedCount 计入此用户）
   * - contributionDistributed = true（防止现有调度器尝试处理）
   * - contributionPerTree = 0（额外安全保障）
   */
  private async ensureAdoptionMarker(
    accountSequence: string,
    orderNo: string,
    paidAt: string | null,
    tx: Prisma.TransactionClient,
  ): Promise<void> {
    // 检查是否已有 marker（通过检查 accountSequence 在大 ID 范围）
    const existingMarker = await tx.syncedAdoption.findFirst({
      where: {
        accountSequence,
        originalAdoptionId: { gte: PRE_PLANTING_SOURCE_ID_OFFSET },
      },
    });

    if (existingMarker) {
      this.logger.debug(
        `[PRE-PLANTING-ORDER] Marker already exists for ${accountSequence}, skipping`,
      );
      return;
    }

    // 同时检查是否已有正常认种记录（已经是正式认种用户）
    const existingAdoption = await tx.syncedAdoption.findFirst({
      where: {
        accountSequence,
        status: 'MINING_ENABLED',
        originalAdoptionId: { lt: PRE_PLANTING_SOURCE_ID_OFFSET },
      },
    });

    if (existingAdoption) {
      this.logger.debug(
        `[PRE-PLANTING-ORDER] User ${accountSequence} already has regular adoption, no marker needed`,
      );
      return;
    }

    // 用 orderNo 的字符编码生成一个稳定的、不与正常认种冲突的唯一 BigInt
    // 格式：PRE_PLANTING_SOURCE_ID_OFFSET + hash(orderNo) % 1_000_000_000n
    const orderNoHash = BigInt(
      orderNo.split('').reduce((acc, c) => (acc * 31 + c.charCodeAt(0)) & 0x7fffffff, 0),
    );
    const markerAdoptionId = PRE_PLANTING_SOURCE_ID_OFFSET + orderNoHash;
    const adoptionDate = paidAt ? new Date(paidAt) : new Date();

    await tx.syncedAdoption.create({
      data: {
        originalAdoptionId: markerAdoptionId,
        accountSequence,
        treeCount: 0,
        adoptionDate,
        status: 'MINING_ENABLED',
        contributionPerTree: 0,
        contributionDistributed: true,
        contributionDistributedAt: new Date(),
        distributionSummary: 'PRE_PLANTING_MARKER',
        sourceSequenceNum: BigInt(0),
        syncedAt: new Date(),
      },
    });

    this.logger.log(
      `[PRE-PLANTING-ORDER] Inserted adoption marker for ${accountSequence}: id=${markerAdoptionId}`,
    );
  }

  /**
   * 检查预种订单是否已经分配过算力（通过 orderNo 查询）
   */
  private async isAlreadyDistributed(orderNo: string): Promise<boolean> {
    try {
      const order = await this.prePlantingPrisma.prePlantingSyncedOrder.findUnique({
        where: { orderNo },
        select: { contributionDistributed: true },
      });
      return order?.contributionDistributed ?? false;
    } catch {
      return false;
    }
  }
}
