import { Injectable, Logger } from '@nestjs/common';
import { UnallocatedContributionRepository, UnallocatedContribution } from '../../infrastructure/persistence/repositories/unallocated-contribution.repository';
import { ContributionAccountRepository } from '../../infrastructure/persistence/repositories/contribution-account.repository';
import { ContributionRecordRepository } from '../../infrastructure/persistence/repositories/contribution-record.repository';
import { SystemAccountRepository } from '../../infrastructure/persistence/repositories/system-account.repository';
import { OutboxRepository } from '../../infrastructure/persistence/repositories/outbox.repository';
import { SyncedDataRepository } from '../../infrastructure/persistence/repositories/synced-data.repository';
import { UnitOfWork } from '../../infrastructure/persistence/unit-of-work/unit-of-work';
import { ContributionRecordAggregate } from '../../domain/aggregates/contribution-record.aggregate';
import { ContributionAccountAggregate, ContributionSourceType } from '../../domain/aggregates/contribution-account.aggregate';
import { ContributionAmount } from '../../domain/value-objects/contribution-amount.vo';
import { DistributionRate } from '../../domain/value-objects/distribution-rate.vo';
import { ContributionCalculatorService } from '../../domain/services/contribution-calculator.service';
import { ContributionRecordSyncedEvent, SystemAccountSyncedEvent, ContributionAccountUpdatedEvent } from '../../domain/events';

/**
 * 奖励补发服务
 * 当用户解锁新的奖励档位时，补发之前所有认种对应的奖励
 */
@Injectable()
export class BonusClaimService {
  private readonly logger = new Logger(BonusClaimService.name);

  constructor(
    private readonly unallocatedContributionRepository: UnallocatedContributionRepository,
    private readonly contributionAccountRepository: ContributionAccountRepository,
    private readonly contributionRecordRepository: ContributionRecordRepository,
    private readonly systemAccountRepository: SystemAccountRepository,
    private readonly outboxRepository: OutboxRepository,
    private readonly syncedDataRepository: SyncedDataRepository,
    private readonly unitOfWork: UnitOfWork,
  ) {}

  /**
   * 检查并处理奖励补发
   * 当用户的直推认种人数变化时调用
   * @param accountSequence 用户账号
   * @param previousCount 之前的直推认种人数
   * @param newCount 新的直推认种人数
   */
  async checkAndClaimBonus(
    accountSequence: string,
    previousCount: number,
    newCount: number,
  ): Promise<void> {
    // 检查是否达到新的解锁条件
    const tiersToClaimList: number[] = [];

    // T2: 直推≥2人认种时解锁
    if (previousCount < 2 && newCount >= 2) {
      tiersToClaimList.push(2);
    }

    // T3: 直推≥4人认种时解锁
    if (previousCount < 4 && newCount >= 4) {
      tiersToClaimList.push(3);
    }

    if (tiersToClaimList.length === 0) {
      return;
    }

    this.logger.log(
      `User ${accountSequence} unlocked bonus tiers: ${tiersToClaimList.join(', ')} ` +
        `(directReferralAdoptedCount: ${previousCount} -> ${newCount})`,
    );

    // 检查是否已在事务中（被 ContributionCalculationService 调用时）
    // 如果已在事务中，直接执行，避免嵌套事务导致超时
    if (this.unitOfWork.isInTransaction()) {
      for (const tier of tiersToClaimList) {
        await this.claimBonusTier(accountSequence, tier);
      }
    } else {
      // 独立调用时，开启新事务
      await this.unitOfWork.executeInTransaction(async () => {
        for (const tier of tiersToClaimList) {
          await this.claimBonusTier(accountSequence, tier);
        }
      });
    }
  }

  /**
   * 补发指定档位的奖励
   */
  private async claimBonusTier(accountSequence: string, bonusTier: number): Promise<void> {
    // 1. 查询待领取的记录
    const pendingRecords = await this.unallocatedContributionRepository.findPendingBonusByAccountSequence(
      accountSequence,
      bonusTier,
    );

    if (pendingRecords.length === 0) {
      this.logger.debug(`No pending T${bonusTier} bonus records for ${accountSequence}`);
      return;
    }

    this.logger.log(
      `Claiming ${pendingRecords.length} T${bonusTier} bonus records for ${accountSequence}`,
    );

    // 2. 查询原始认种数据，获取 treeCount 和 baseContribution
    const adoptionDataMap = new Map<string, { treeCount: number; baseContribution: ContributionAmount }>();
    for (const pending of pendingRecords) {
      const adoptionIdStr = pending.sourceAdoptionId.toString();
      if (!adoptionDataMap.has(adoptionIdStr)) {
        const adoption = await this.syncedDataRepository.findSyncedAdoptionByOriginalId(pending.sourceAdoptionId);
        if (adoption) {
          adoptionDataMap.set(adoptionIdStr, {
            treeCount: adoption.treeCount,
            baseContribution: new ContributionAmount(adoption.contributionPerTree),
          });
        } else {
          // 如果找不到原始认种数据，使用默认值并记录警告
          this.logger.warn(`Adoption not found for sourceAdoptionId: ${pending.sourceAdoptionId}, using default values`);
          adoptionDataMap.set(adoptionIdStr, {
            treeCount: 0,
            baseContribution: new ContributionAmount(0),
          });
        }
      }
    }

    // 3. 创建贡献值记录
    const contributionRecords: ContributionRecordAggregate[] = [];
    for (const pending of pendingRecords) {
      const adoptionData = adoptionDataMap.get(pending.sourceAdoptionId.toString())!;
      const record = new ContributionRecordAggregate({
        accountSequence: accountSequence,
        sourceType: ContributionSourceType.TEAM_BONUS,
        sourceAdoptionId: pending.sourceAdoptionId,
        sourceAccountSequence: pending.sourceAccountSequence,
        treeCount: adoptionData.treeCount,
        baseContribution: adoptionData.baseContribution,
        distributionRate: DistributionRate.BONUS_PER,
        bonusTier: bonusTier,
        amount: pending.amount,
        effectiveDate: pending.effectiveDate,
        expireDate: pending.expireDate,
      });
      contributionRecords.push(record);
    }

    // 4. 保存贡献值记录
    const savedRecords = await this.contributionRecordRepository.saveMany(contributionRecords);

    // 5. 更新用户的贡献值账户
    let totalAmount = new ContributionAmount(0);
    for (const pending of pendingRecords) {
      totalAmount = new ContributionAmount(totalAmount.value.plus(pending.amount.value));
    }

    await this.contributionAccountRepository.updateContribution(
      accountSequence,
      ContributionSourceType.TEAM_BONUS,
      totalAmount,
      null,
      bonusTier,
    );

    // 6. 标记待领取记录为已分配
    const pendingIds = pendingRecords.map((r) => r.id);
    await this.unallocatedContributionRepository.claimBonusRecords(pendingIds, accountSequence);

    // 7. 从 HEADQUARTERS 减少算力并删除明细记录
    await this.systemAccountRepository.subtractContribution('HEADQUARTERS', null, totalAmount);
    for (const pending of pendingRecords) {
      await this.systemAccountRepository.deleteContributionRecordsByAdoption(
        'HEADQUARTERS',
        null,
        pending.sourceAdoptionId,
        pending.sourceAccountSequence,
      );
    }

    // 8. 发布 HEADQUARTERS 账户更新事件
    const headquartersAccount = await this.systemAccountRepository.findByTypeAndRegion('HEADQUARTERS', null);
    if (headquartersAccount) {
      const hqEvent = new SystemAccountSyncedEvent(
        'HEADQUARTERS',
        null,
        headquartersAccount.name,
        headquartersAccount.contributionBalance.value.toString(),
        headquartersAccount.createdAt,
      );
      await this.outboxRepository.save({
        aggregateType: SystemAccountSyncedEvent.AGGREGATE_TYPE,
        aggregateId: 'HEADQUARTERS',
        eventType: SystemAccountSyncedEvent.EVENT_TYPE,
        payload: hqEvent.toPayload(),
      });
    }

    // 9. 发布事件到 Kafka（通过 Outbox）
    await this.publishBonusClaimEvents(accountSequence, savedRecords, pendingRecords);

    this.logger.log(
      `Claimed T${bonusTier} bonus for ${accountSequence}: ` +
        `${pendingRecords.length} records, total amount: ${totalAmount.value.toString()}`,
    );
  }

  /**
   * 发布补发事件
   */
  private async publishBonusClaimEvents(
    accountSequence: string,
    savedRecords: ContributionRecordAggregate[],
    pendingRecords: UnallocatedContribution[],
  ): Promise<void> {
    // 1. 发布贡献值记录同步事件（用于 mining-admin-service CDC）
    for (const record of savedRecords) {
      const event = new ContributionRecordSyncedEvent(
        record.id!,
        record.accountSequence,
        record.sourceType,
        record.sourceAdoptionId,
        record.sourceAccountSequence,
        record.treeCount,
        record.baseContribution.value.toString(),
        record.distributionRate.value.toString(),
        record.levelDepth,
        record.bonusTier,
        record.amount.value.toString(),
        record.effectiveDate,
        record.expireDate,
        record.isExpired,
        record.createdAt,
      );

      await this.outboxRepository.save({
        aggregateType: ContributionRecordSyncedEvent.AGGREGATE_TYPE,
        aggregateId: record.id!.toString(),
        eventType: ContributionRecordSyncedEvent.EVENT_TYPE,
        payload: event.toPayload(),
      });
    }

    // 2. 发布补发事件到 mining-wallet-service
    const userContributions = savedRecords.map((record, index) => ({
      accountSequence: record.accountSequence,
      contributionType: 'TEAM_BONUS',
      amount: record.amount.value.toString(),
      bonusTier: record.bonusTier,
      effectiveDate: record.effectiveDate.toISOString(),
      expireDate: record.expireDate.toISOString(),
      sourceAdoptionId: record.sourceAdoptionId.toString(),
      sourceAccountSequence: record.sourceAccountSequence,
      isBackfill: true, // 标记为补发
    }));

    const eventId = `bonus-claim-${accountSequence}-${Date.now()}`;
    const payload = {
      eventType: 'BonusClaimed',
      eventId,
      timestamp: new Date().toISOString(),
      payload: {
        accountSequence,
        bonusTier: savedRecords[0]?.bonusTier,
        claimedCount: savedRecords.length,
        userContributions,
      },
    };

    await this.outboxRepository.save({
      eventType: 'BonusClaimed',
      topic: 'contribution.bonus.claimed',
      key: accountSequence,
      payload,
      aggregateId: accountSequence,
      aggregateType: 'ContributionAccount',
    });
  }

  // ========== LEVEL_OVERFLOW 回收逻辑 ==========

  /**
   * 回收已解锁层级的 LEVEL_OVERFLOW 记录
   * 处理场景：下级认种时上级 unlocked_level_depth 不足，产生 LEVEL_OVERFLOW；
   *           后续上级解锁到足够层级后，这些 PENDING 记录需要被回收分配
   * @param limit 每次扫描的最大账户数
   * @returns 回收的记录总数
   */
  async reclaimLevelOverflows(limit: number = 100): Promise<number> {
    // 1. 查找有 PENDING LEVEL_OVERFLOW 记录的账户
    const accountSequences = await this.unallocatedContributionRepository
      .findAccountSequencesWithPendingLevelOverflow(limit);

    if (accountSequences.length === 0) {
      return 0;
    }

    this.logger.log(`[OverflowReclaim] Found ${accountSequences.length} accounts with pending LEVEL_OVERFLOW`);

    let totalReclaimed = 0;
    let errorCount = 0;

    for (const accountSequence of accountSequences) {
      try {
        const account = await this.contributionAccountRepository.findByAccountSequence(accountSequence);
        if (!account || account.unlockedLevelDepth === 0) {
          continue;
        }

        // 只回收已解锁层级范围内的 overflow
        await this.unitOfWork.executeInTransaction(async () => {
          const claimed = await this.claimLevelContributions(
            accountSequence,
            1,
            account.unlockedLevelDepth,
          );

          if (claimed > 0) {
            totalReclaimed += claimed;
            // 重新读取账户（claimLevelContributions 已更新余额），发布更新事件
            const updatedAccount = await this.contributionAccountRepository
              .findByAccountSequence(accountSequence);
            if (updatedAccount) {
              await this.publishContributionAccountUpdatedEvent(updatedAccount);
            }
          }
        });
      } catch (error) {
        errorCount++;
        this.logger.error(`[OverflowReclaim] Failed for account ${accountSequence}`, error);
      }
    }

    this.logger.log(
      `[OverflowReclaim] Completed: ${totalReclaimed} records reclaimed, ${errorCount} errors`,
    );
    return totalReclaimed;
  }

  // ========== 定时任务补发逻辑 ==========

  private readonly domainCalculator = new ContributionCalculatorService();

  /**
   * 处理单个账户的补发逻辑
   * 检查是否有新解锁的层级或奖励档位，并进行补发
   * @returns 是否有补发
   */
  async processBackfillForAccount(accountSequence: string): Promise<boolean> {
    const account = await this.contributionAccountRepository.findByAccountSequence(accountSequence);
    if (!account) {
      return false;
    }

    // 重新计算直推认种用户数
    const currentDirectReferralAdoptedCount = await this.syncedDataRepository.getDirectReferralAdoptedCount(
      accountSequence,
    );

    // 计算应该解锁的层级深度和奖励档位
    const expectedLevelDepth = this.domainCalculator.calculateUnlockedLevelDepth(currentDirectReferralAdoptedCount);
    const expectedBonusTiers = this.domainCalculator.calculateUnlockedBonusTiers(
      account.hasAdopted,
      currentDirectReferralAdoptedCount,
    );

    // 保存原始值（level 事务中 updateAccountUnlockStatus 会通过 incrementDirectReferralAdoptedCount
    // 同时修改 unlockedLevelDepth 和 unlockedBonusTiers，导致 bonus 分支条件失效）
    const originalDirectReferralAdoptedCount = account.directReferralAdoptedCount;
    const originalUnlockedBonusTiers = account.unlockedBonusTiers;

    this.logger.log(
      `[Backfill] Checking account ${accountSequence}: ` +
        `hasAdopted=${account.hasAdopted}, ` +
        `directReferralAdoptedCount=${originalDirectReferralAdoptedCount} -> ${currentDirectReferralAdoptedCount}, ` +
        `unlockedLevelDepth=${account.unlockedLevelDepth} (expected=${expectedLevelDepth}), ` +
        `unlockedBonusTiers=${originalUnlockedBonusTiers} (expected=${expectedBonusTiers})`,
    );

    let hasBackfill = false;

    // 检查是否需要补发层级贡献值
    if (expectedLevelDepth > account.unlockedLevelDepth) {
      this.logger.log(
        `[Backfill] Account ${accountSequence} level unlock: ${account.unlockedLevelDepth} -> ${expectedLevelDepth} ` +
          `(directReferralAdoptedCount: ${originalDirectReferralAdoptedCount} -> ${currentDirectReferralAdoptedCount})`,
      );

      await this.unitOfWork.executeInTransaction(async () => {
        // 补发层级贡献值
        const levelClaimed = await this.claimLevelContributions(
          accountSequence,
          account.unlockedLevelDepth + 1,
          expectedLevelDepth,
        );

        if (levelClaimed > 0) {
          hasBackfill = true;
        }

        // 更新账户的直推认种数和解锁状态
        await this.updateAccountUnlockStatus(
          account,
          currentDirectReferralAdoptedCount,
          expectedLevelDepth,
          expectedBonusTiers,
        );
      });

      this.logger.log(
        `[Backfill] Account ${accountSequence} level backfill transaction completed. ` +
          `After mutation: directReferralAdoptedCount=${account.directReferralAdoptedCount}, ` +
          `unlockedLevelDepth=${account.unlockedLevelDepth}, unlockedBonusTiers=${account.unlockedBonusTiers}`,
      );
    }

    // 检查是否需要补发奖励档位（使用原始值，因为 level 分支的 updateAccountUnlockStatus
    // 会同时把 unlockedBonusTiers 更新到 expectedBonusTiers，导致此条件永远为 false）
    this.logger.debug(
      `[Backfill] Account ${accountSequence} bonus check: ` +
        `expectedBonusTiers(${expectedBonusTiers}) > originalUnlockedBonusTiers(${originalUnlockedBonusTiers}) = ${expectedBonusTiers > originalUnlockedBonusTiers}`,
    );
    if (expectedBonusTiers > originalUnlockedBonusTiers) {
      this.logger.log(
        `[Backfill] Account ${accountSequence} bonus unlock: ${originalUnlockedBonusTiers} -> ${expectedBonusTiers} ` +
          `(directReferralAdoptedCount: ${originalDirectReferralAdoptedCount} -> ${currentDirectReferralAdoptedCount})`,
      );

      // 使用原始直推认种数，确保 checkAndClaimBonus 能正确判断需要解锁的档位
      await this.checkAndClaimBonus(
        accountSequence,
        originalDirectReferralAdoptedCount,
        currentDirectReferralAdoptedCount,
      );
      hasBackfill = true;

      // 如果只有奖励档位需要补发（层级已经是最新的），也需要更新账户状态
      if (expectedLevelDepth <= account.unlockedLevelDepth) {
        await this.unitOfWork.executeInTransaction(async () => {
          await this.updateAccountUnlockStatus(
            account,
            currentDirectReferralAdoptedCount,
            expectedLevelDepth,
            expectedBonusTiers,
          );
        });
      }
    }

    this.logger.log(
      `[Backfill] Account ${accountSequence} backfill result: hasBackfill=${hasBackfill}`,
    );
    return hasBackfill;
  }

  /**
   * 补发层级贡献值
   * @param accountSequence 用户账号
   * @param minLevel 最小层级（包含）
   * @param maxLevel 最大层级（包含）
   * @returns 补发的记录数
   */
  private async claimLevelContributions(
    accountSequence: string,
    minLevel: number,
    maxLevel: number,
  ): Promise<number> {
    // 1. 查询待领取的层级贡献值记录
    const pendingRecords = await this.unallocatedContributionRepository.findPendingLevelByAccountSequence(
      accountSequence,
      minLevel,
      maxLevel,
    );

    if (pendingRecords.length === 0) {
      this.logger.debug(`[Backfill] No pending level records for ${accountSequence} (levels ${minLevel}-${maxLevel})`);
      return 0;
    }

    this.logger.log(
      `[Backfill] Claiming ${pendingRecords.length} level records for ${accountSequence} (levels ${minLevel}-${maxLevel})`,
    );

    // 2. 查询原始认种数据，获取 treeCount 和 baseContribution
    const adoptionDataMap = new Map<string, { treeCount: number; baseContribution: ContributionAmount }>();
    for (const pending of pendingRecords) {
      const adoptionIdStr = pending.sourceAdoptionId.toString();
      if (!adoptionDataMap.has(adoptionIdStr)) {
        const adoption = await this.syncedDataRepository.findSyncedAdoptionByOriginalId(pending.sourceAdoptionId);
        if (adoption) {
          adoptionDataMap.set(adoptionIdStr, {
            treeCount: adoption.treeCount,
            baseContribution: new ContributionAmount(adoption.contributionPerTree),
          });
        } else {
          this.logger.warn(`[Backfill] Adoption not found for sourceAdoptionId: ${pending.sourceAdoptionId}`);
          adoptionDataMap.set(adoptionIdStr, {
            treeCount: 0,
            baseContribution: new ContributionAmount(0),
          });
        }
      }
    }

    // 3. 创建贡献值记录
    const contributionRecords: ContributionRecordAggregate[] = [];
    for (const pending of pendingRecords) {
      const adoptionData = adoptionDataMap.get(pending.sourceAdoptionId.toString())!;
      const record = new ContributionRecordAggregate({
        accountSequence: accountSequence,
        sourceType: ContributionSourceType.TEAM_LEVEL,
        sourceAdoptionId: pending.sourceAdoptionId,
        sourceAccountSequence: pending.sourceAccountSequence,
        treeCount: adoptionData.treeCount,
        baseContribution: adoptionData.baseContribution,
        distributionRate: DistributionRate.LEVEL_PER,
        levelDepth: pending.levelDepth!,
        amount: pending.amount,
        effectiveDate: pending.effectiveDate,
        expireDate: pending.expireDate,
      });
      contributionRecords.push(record);
    }

    // 4. 保存贡献值记录
    const savedRecords = await this.contributionRecordRepository.saveMany(contributionRecords);

    // 5. 更新用户的贡献值账户（按层级分别更新）
    for (const pending of pendingRecords) {
      await this.contributionAccountRepository.updateContribution(
        accountSequence,
        ContributionSourceType.TEAM_LEVEL,
        pending.amount,
        pending.levelDepth,
        null,
      );
    }

    // 6. 标记待领取记录为已分配
    const pendingIds = pendingRecords.map((r) => r.id);
    await this.unallocatedContributionRepository.claimLevelRecords(pendingIds, accountSequence);

    // 7. 计算总金额用于从 HEADQUARTERS 扣除
    let totalAmount = new ContributionAmount(0);
    for (const pending of pendingRecords) {
      totalAmount = new ContributionAmount(totalAmount.value.plus(pending.amount.value));
    }

    // 8. 从 HEADQUARTERS 减少算力并删除明细记录
    await this.systemAccountRepository.subtractContribution('HEADQUARTERS', null, totalAmount);
    for (const pending of pendingRecords) {
      await this.systemAccountRepository.deleteContributionRecordsByAdoption(
        'HEADQUARTERS',
        null,
        pending.sourceAdoptionId,
        pending.sourceAccountSequence,
      );
    }

    // 9. 发布 HEADQUARTERS 账户更新事件
    const headquartersAccount = await this.systemAccountRepository.findByTypeAndRegion('HEADQUARTERS', null);
    if (headquartersAccount) {
      const hqEvent = new SystemAccountSyncedEvent(
        'HEADQUARTERS',
        null,
        headquartersAccount.name,
        headquartersAccount.contributionBalance.value.toString(),
        headquartersAccount.createdAt,
      );
      await this.outboxRepository.save({
        aggregateType: SystemAccountSyncedEvent.AGGREGATE_TYPE,
        aggregateId: 'HEADQUARTERS',
        eventType: SystemAccountSyncedEvent.EVENT_TYPE,
        payload: hqEvent.toPayload(),
      });
    }

    // 10. 发布贡献值记录同步事件
    await this.publishLevelClaimEvents(accountSequence, savedRecords, pendingRecords);

    this.logger.log(
      `[Backfill] Claimed level contributions for ${accountSequence}: ` +
        `${pendingRecords.length} records, total amount: ${totalAmount.value.toString()}`,
    );

    return pendingRecords.length;
  }

  /**
   * 更新账户的解锁状态
   */
  private async updateAccountUnlockStatus(
    account: ContributionAccountAggregate,
    newDirectReferralAdoptedCount: number,
    expectedLevelDepth: number,
    expectedBonusTiers: number,
  ): Promise<void> {
    // 使用 setDirectReferralAdoptedCount 无条件重算解锁状态。
    //
    // 不能用「if (newCount > previousCount) increment」的方式，原因：
    //   当直推已全部认种（DB count 已正确）但 markAsAdopted() 在此之后才
    //   被调用时，markAsAdopted 会硬编码 level=5/bonus=1，导致 level 错误，
    //   但 count 不变，条件判断永远为 false，backfill 无法修复。
    //
    // setDirectReferralAdoptedCount 内部调用 updateUnlockStatus()，
    // 无论 count 是否变化都会根据 hasAdopted + count 重新计算正确的
    // unlockedLevelDepth 和 unlockedBonusTiers。
    account.setDirectReferralAdoptedCount(newDirectReferralAdoptedCount);

    await this.contributionAccountRepository.save(account);

    // 发布账户更新事件
    await this.publishContributionAccountUpdatedEvent(account);
  }

  /**
   * 发布层级补发事件
   */
  private async publishLevelClaimEvents(
    accountSequence: string,
    savedRecords: ContributionRecordAggregate[],
    pendingRecords: UnallocatedContribution[],
  ): Promise<void> {
    // 1. 发布贡献值记录同步事件（用于 mining-admin-service CDC）
    for (const record of savedRecords) {
      const event = new ContributionRecordSyncedEvent(
        record.id!,
        record.accountSequence,
        record.sourceType,
        record.sourceAdoptionId,
        record.sourceAccountSequence,
        record.treeCount,
        record.baseContribution.value.toString(),
        record.distributionRate.value.toString(),
        record.levelDepth,
        record.bonusTier,
        record.amount.value.toString(),
        record.effectiveDate,
        record.expireDate,
        record.isExpired,
        record.createdAt,
      );

      await this.outboxRepository.save({
        aggregateType: ContributionRecordSyncedEvent.AGGREGATE_TYPE,
        aggregateId: record.id!.toString(),
        eventType: ContributionRecordSyncedEvent.EVENT_TYPE,
        payload: event.toPayload(),
      });
    }

    // 2. 发布补发事件到 mining-wallet-service
    const userContributions = savedRecords.map((record) => ({
      accountSequence: record.accountSequence,
      contributionType: 'TEAM_LEVEL',
      amount: record.amount.value.toString(),
      levelDepth: record.levelDepth,
      effectiveDate: record.effectiveDate.toISOString(),
      expireDate: record.expireDate.toISOString(),
      sourceAdoptionId: record.sourceAdoptionId.toString(),
      sourceAccountSequence: record.sourceAccountSequence,
      isBackfill: true, // 标记为补发
    }));

    const eventId = `level-claim-${accountSequence}-${Date.now()}`;
    const payload = {
      eventType: 'LevelClaimed',
      eventId,
      timestamp: new Date().toISOString(),
      payload: {
        accountSequence,
        claimedCount: savedRecords.length,
        userContributions,
      },
    };

    await this.outboxRepository.save({
      eventType: 'LevelClaimed',
      topic: 'contribution.level.claimed',
      key: accountSequence,
      payload,
      aggregateId: accountSequence,
      aggregateType: 'ContributionAccount',
    });
  }

  /**
   * 发布贡献值账户更新事件
   */
  private async publishContributionAccountUpdatedEvent(
    account: ContributionAccountAggregate,
  ): Promise<void> {
    const totalContribution = account.personalContribution.value
      .plus(account.totalLevelPending.value)
      .plus(account.totalBonusPending.value);

    const event = new ContributionAccountUpdatedEvent(
      account.accountSequence,
      account.personalContribution.value.toString(),
      account.totalLevelPending.value.toString(),
      account.totalBonusPending.value.toString(),
      totalContribution.toString(),
      account.effectiveContribution.value.toString(),
      account.hasAdopted,
      account.directReferralAdoptedCount,
      account.unlockedLevelDepth,
      account.unlockedBonusTiers,
      account.createdAt,
    );

    await this.outboxRepository.save({
      aggregateType: ContributionAccountUpdatedEvent.AGGREGATE_TYPE,
      aggregateId: account.accountSequence,
      eventType: ContributionAccountUpdatedEvent.EVENT_TYPE,
      payload: event.toPayload(),
    });
  }
}
