import { Injectable, Logger } from '@nestjs/common';
import { CDCEvent, TransactionClient } from '../../infrastructure/kafka/cdc-consumer.service';
import { ReferralSyncedEvent } from '../../domain/events/referral-synced.event';

/**
 * 引荐关系 CDC 事件处理器
 * 处理从1.0 referral-service同步过来的referral_relationships数据
 *
 * 设计说明：100%同步数据，不跳过任何字段更新
 */
@Injectable()
export class ReferralSyncedHandler {
  private readonly logger = new Logger(ReferralSyncedHandler.name);

  constructor() {}

  async handle(event: CDCEvent, tx: TransactionClient): Promise<void> {
    const { op, before, after } = event.payload;

    this.logger.log(`[CDC] Referral event received: op=${op}, seq=${event.sequenceNum}`);
    this.logger.debug(`[CDC] Referral event payload: ${JSON.stringify(after || before)}`);

    try {
      switch (op) {
        case 'c': // create
        case 'r': // read (snapshot)
          await this.handleCreate(after, event.sequenceNum, tx);
          break;
        case 'u': // update
          await this.handleUpdate(after, event.sequenceNum, tx);
          break;
        case 'd': // delete
          await this.handleDelete(before);
          break;
        default:
          this.logger.warn(`[CDC] Unknown CDC operation: ${op}`);
      }
    } catch (error) {
      this.logger.error(`[CDC] Failed to handle referral CDC event, op=${op}, seq=${event.sequenceNum}`, error);
      throw error;
    }
  }

  private async handleCreate(data: any, sequenceNum: bigint, tx: TransactionClient): Promise<void> {
    if (!data) {
      this.logger.warn(`[CDC] Referral create: empty data received`);
      return;
    }

    const accountSequence = data.account_sequence || data.accountSequence;
    const originalUserId = data.user_id || data.userId;
    const referrerUserId = data.referrer_id || data.referrerId;
    const ancestorPathArray = data.ancestor_path || data.ancestorPath;
    const depth = data.depth ?? 0;

    this.logger.log(`[CDC] Referral create: account=${accountSequence}, userId=${originalUserId}, referrerId=${referrerUserId}, depth=${depth}`);

    if (!accountSequence) {
      this.logger.warn(`[CDC] Invalid referral data: missing account_sequence`, { data });
      return;
    }

    const ancestorPath = this.convertAncestorPath(ancestorPathArray);

    // 尝试查找推荐人的 account_sequence
    let referrerAccountSequence: string | null = null;
    if (referrerUserId) {
      const referrer = await tx.syncedReferral.findFirst({
        where: { originalUserId: BigInt(referrerUserId) },
      });
      if (referrer) {
        referrerAccountSequence = referrer.accountSequence;
      }
    }

    // 100%同步数据
    await tx.syncedReferral.upsert({
      where: { accountSequence },
      create: {
        accountSequence,
        referrerAccountSequence,
        referrerUserId: referrerUserId ? BigInt(referrerUserId) : null,
        originalUserId: originalUserId ? BigInt(originalUserId) : null,
        ancestorPath,
        depth,
        sourceSequenceNum: sequenceNum,
        syncedAt: new Date(),
      },
      update: {
        referrerAccountSequence,
        referrerUserId: referrerUserId ? BigInt(referrerUserId) : null,
        originalUserId: originalUserId ? BigInt(originalUserId) : null,
        ancestorPath,
        depth,
        sourceSequenceNum: sequenceNum,
        syncedAt: new Date(),
      },
    });

    this.logger.log(`[CDC] Referral synced: ${accountSequence}, referrerId=${referrerUserId || 'none'}, depth=${depth}`);

    // 发布 ReferralSynced outbox 事件，实时同步到 mining-admin-service
    await this.publishReferralOutboxEvent(tx, accountSequence, referrerAccountSequence, referrerUserId ? BigInt(referrerUserId) : null, originalUserId ? BigInt(originalUserId) : null, ancestorPath, depth);
  }

  private async handleUpdate(data: any, sequenceNum: bigint, tx: TransactionClient): Promise<void> {
    if (!data) {
      this.logger.warn(`[CDC] Referral update: empty data received`);
      return;
    }

    const accountSequence = data.account_sequence || data.accountSequence;
    const originalUserId = data.user_id || data.userId;
    const referrerUserId = data.referrer_id || data.referrerId;
    const ancestorPathArray = data.ancestor_path || data.ancestorPath;
    const depth = data.depth ?? 0;

    this.logger.log(`[CDC] Referral update: account=${accountSequence}, referrerId=${referrerUserId}, depth=${depth}`);

    if (!accountSequence) {
      this.logger.warn(`[CDC] Invalid referral update data: missing account_sequence`, { data });
      return;
    }

    const ancestorPath = this.convertAncestorPath(ancestorPathArray);

    // 尝试查找推荐人的 account_sequence
    let referrerAccountSequence: string | null = null;
    if (referrerUserId) {
      const referrer = await tx.syncedReferral.findFirst({
        where: { originalUserId: BigInt(referrerUserId) },
      });
      if (referrer) {
        referrerAccountSequence = referrer.accountSequence;
      }
    }

    // 100%同步数据
    await tx.syncedReferral.upsert({
      where: { accountSequence },
      create: {
        accountSequence,
        referrerAccountSequence,
        referrerUserId: referrerUserId ? BigInt(referrerUserId) : null,
        originalUserId: originalUserId ? BigInt(originalUserId) : null,
        ancestorPath,
        depth,
        sourceSequenceNum: sequenceNum,
        syncedAt: new Date(),
      },
      update: {
        referrerAccountSequence,
        referrerUserId: referrerUserId ? BigInt(referrerUserId) : null,
        originalUserId: originalUserId ? BigInt(originalUserId) : null,
        ancestorPath,
        depth,
        sourceSequenceNum: sequenceNum,
        syncedAt: new Date(),
      },
    });

    this.logger.log(`[CDC] Referral synced: ${accountSequence}`);

    // 发布 ReferralSynced outbox 事件，实时同步到 mining-admin-service
    await this.publishReferralOutboxEvent(tx, accountSequence, referrerAccountSequence, referrerUserId ? BigInt(referrerUserId) : null, originalUserId ? BigInt(originalUserId) : null, ancestorPath, depth);
  }

  private async handleDelete(data: any): Promise<void> {
    if (!data) {
      this.logger.warn(`[CDC] Referral delete: empty data received`);
      return;
    }
    const accountSequence = data.account_sequence || data.accountSequence;
    // 引荐关系删除需要特殊处理
    this.logger.warn(`[CDC] Referral delete event received: ${accountSequence} (not processed, keeping history)`);
  }

  /**
   * 在事务内发布 ReferralSynced outbox 事件
   * 确保 mining-admin-service 能实时收到推荐关系变更
   */
  private async publishReferralOutboxEvent(
    tx: TransactionClient,
    accountSequence: string,
    referrerAccountSequence: string | null,
    referrerUserId: bigint | null,
    originalUserId: bigint | null,
    ancestorPath: string | null,
    depth: number,
  ): Promise<void> {
    const event = new ReferralSyncedEvent(
      accountSequence,
      referrerAccountSequence,
      referrerUserId,
      originalUserId,
      ancestorPath,
      depth,
    );

    await tx.outboxEvent.create({
      data: {
        aggregateType: ReferralSyncedEvent.AGGREGATE_TYPE,
        aggregateId: accountSequence,
        eventType: ReferralSyncedEvent.EVENT_TYPE,
        topic: 'contribution.referralsynced',
        key: accountSequence,
        payload: event.toPayload(),
        status: 'PENDING',
      },
    });

    this.logger.debug(`[CDC] Published ReferralSynced outbox event: account=${accountSequence}`);
  }

  /**
   * 将 BigInt[] 数组转换为逗号分隔的字符串
   * @param ancestorPath BigInt 数组或 null
   * @returns 逗号分隔的字符串或 null
   */
  private convertAncestorPath(ancestorPath: any): string | null {
    if (!ancestorPath) return null;

    // 处理可能的数组格式
    if (Array.isArray(ancestorPath)) {
      return ancestorPath.map((id) => String(id)).join(',');
    }

    // 如果已经是字符串 (可能是 PostgreSQL 数组的字符串表示)
    if (typeof ancestorPath === 'string') {
      // PostgreSQL 数组格式: {1,2,3} 或 [1,2,3]
      const cleaned = ancestorPath.replace(/[{}\[\]]/g, '');
      return cleaned || null;
    }

    return null;
  }
}
