import { Injectable, Logger } from '@nestjs/common';
import { ContributionCalculatorService, ContributionDistributionResult } from '../../domain/services/contribution-calculator.service';
import { ContributionAccountRepository } from '../../infrastructure/persistence/repositories/contribution-account.repository';
import { ContributionRecordRepository } from '../../infrastructure/persistence/repositories/contribution-record.repository';
import { SyncedDataRepository } from '../../infrastructure/persistence/repositories/synced-data.repository';
import { UnallocatedContributionRepository } from '../../infrastructure/persistence/repositories/unallocated-contribution.repository';
import { SystemAccountRepository } from '../../infrastructure/persistence/repositories/system-account.repository';
import { OutboxRepository } from '../../infrastructure/persistence/repositories/outbox.repository';
import { UnitOfWork } from '../../infrastructure/persistence/unit-of-work/unit-of-work';
import { ContributionAccountAggregate, ContributionSourceType } from '../../domain/aggregates/contribution-account.aggregate';
import { SyncedReferral } from '../../domain/repositories/synced-data.repository.interface';

/**
 * 算力计算应用服务
 * 协调领域服务和仓库，完成算力计算的完整流程
 */
@Injectable()
export class ContributionCalculationService {
  private readonly logger = new Logger(ContributionCalculationService.name);
  private readonly domainCalculator = new ContributionCalculatorService();

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

  /**
   * 为认种计算并分配算力
   */
  async calculateForAdoption(originalAdoptionId: bigint): Promise<void> {
    // 检查是否已经处理过
    const exists = await this.contributionRecordRepository.existsBySourceAdoptionId(originalAdoptionId);
    if (exists) {
      this.logger.debug(`Adoption ${originalAdoptionId} already processed, skipping`);
      return;
    }

    // 获取认种数据
    const adoption = await this.syncedDataRepository.findSyncedAdoptionByOriginalId(originalAdoptionId);
    if (!adoption) {
      throw new Error(`Adoption not found: ${originalAdoptionId}`);
    }

    // 获取认种用户的引荐关系
    const userReferral = await this.syncedDataRepository.findSyncedReferralByAccountSequence(adoption.accountSequence);

    // 获取上线链条（最多15级）
    let ancestorChain: SyncedReferral[] = [];
    if (userReferral?.referrerAccountSequence) {
      ancestorChain = await this.buildAncestorChain(userReferral.referrerAccountSequence);
    }

    // 获取上线的算力账户（用于判断解锁状态）
    const ancestorAccountSequences = ancestorChain.map((a) => a.accountSequence);
    const ancestorAccounts = await this.contributionAccountRepository.findByAccountSequences(ancestorAccountSequences);

    // 执行算力计算
    const result = this.domainCalculator.calculateAdoptionContribution(adoption, ancestorChain, ancestorAccounts);

    // 在事务中保存所有结果
    await this.unitOfWork.executeInTransaction(async () => {
      await this.saveDistributionResult(result, adoption.originalAdoptionId, adoption.accountSequence);

      // 标记认种已处理
      await this.syncedDataRepository.markAdoptionContributionDistributed(adoption.originalAdoptionId);

      // 更新认种人的解锁状态（如果是首次认种）
      await this.updateAdopterUnlockStatus(adoption.accountSequence);

      // 更新直接上线的解锁状态
      if (userReferral?.referrerAccountSequence) {
        await this.updateReferrerUnlockStatus(userReferral.referrerAccountSequence);
      }

      // 发布事件到 Outbox
      await this.outboxRepository.save({
        aggregateType: 'ContributionAccount',
        aggregateId: adoption.accountSequence,
        eventType: 'ContributionCalculated',
        payload: {
          accountSequence: adoption.accountSequence,
          sourceAdoptionId: originalAdoptionId.toString(),
          personalContribution: result.personalRecord.amount.value.toString(),
          teamLevelCount: result.teamLevelRecords.length,
          teamBonusCount: result.teamBonusRecords.length,
          unallocatedCount: result.unallocatedContributions.length,
          calculatedAt: new Date().toISOString(),
        },
      });
    });

    this.logger.log(
      `Contribution calculated for adoption ${originalAdoptionId}: ` +
        `personal=${result.personalRecord.amount.value}, ` +
        `teamLevel=${result.teamLevelRecords.length}, ` +
        `teamBonus=${result.teamBonusRecords.length}, ` +
        `unallocated=${result.unallocatedContributions.length}`,
    );
  }

  /**
   * 批量计算未处理的认种
   */
  async processUndistributedAdoptions(batchSize: number = 100): Promise<number> {
    const undistributed = await this.syncedDataRepository.findUndistributedAdoptions(batchSize);

    let processedCount = 0;
    for (const adoption of undistributed) {
      try {
        await this.calculateForAdoption(adoption.originalAdoptionId);
        processedCount++;
      } catch (error) {
        this.logger.error(`Failed to process adoption ${adoption.originalAdoptionId}`, error);
        // 继续处理下一个
      }
    }

    return processedCount;
  }

  /**
   * 重新计算指定账户的全部算力
   * 用于修正或审计
   */
  async recalculateForAccount(accountSequence: string): Promise<void> {
    const adoptions = await this.syncedDataRepository.findAdoptionsByAccountSequence(accountSequence);

    for (const adoption of adoptions) {
      // 这里需要特殊处理：先清除旧记录，再重新计算
      // TODO: 实现完整的重新计算逻辑
      this.logger.warn(`Recalculation for ${accountSequence} not fully implemented yet`);
    }
  }

  /**
   * 构建上线链条
   */
  private async buildAncestorChain(startAccountSequence: string): Promise<SyncedReferral[]> {
    return await this.syncedDataRepository.findAncestorChain(startAccountSequence, 15);
  }

  /**
   * 保存分配结果
   */
  private async saveDistributionResult(
    result: ContributionDistributionResult,
    sourceAdoptionId: bigint,
    sourceAccountSequence: string,
  ): Promise<void> {
    // 1. 保存个人算力记录
    await this.contributionRecordRepository.save(result.personalRecord);

    // 更新个人算力账户
    let account = await this.contributionAccountRepository.findByAccountSequence(
      result.personalRecord.accountSequence,
    );
    if (!account) {
      account = ContributionAccountAggregate.create(result.personalRecord.accountSequence);
    }
    account.addPersonalContribution(result.personalRecord.amount);
    await this.contributionAccountRepository.save(account);

    // 2. 保存团队层级算力记录
    if (result.teamLevelRecords.length > 0) {
      await this.contributionRecordRepository.saveMany(result.teamLevelRecords);

      // 更新各上线的算力账户
      for (const record of result.teamLevelRecords) {
        await this.contributionAccountRepository.updateContribution(
          record.accountSequence,
          ContributionSourceType.TEAM_LEVEL,
          record.amount,
        );
      }
    }

    // 3. 保存团队奖励算力记录
    if (result.teamBonusRecords.length > 0) {
      await this.contributionRecordRepository.saveMany(result.teamBonusRecords);

      // 更新直接上线的算力账户
      for (const record of result.teamBonusRecords) {
        await this.contributionAccountRepository.updateContribution(
          record.accountSequence,
          ContributionSourceType.TEAM_BONUS,
          record.amount,
        );
      }
    }

    // Get effectiveDate and expireDate from the personal record
    const effectiveDate = result.personalRecord.effectiveDate;
    const expireDate = result.personalRecord.expireDate;

    // 4. 保存未分配算力
    if (result.unallocatedContributions.length > 0) {
      await this.unallocatedContributionRepository.saveMany(
        result.unallocatedContributions.map((u) => ({
          ...u,
          sourceAdoptionId,
          sourceAccountSequence,
          effectiveDate,
          expireDate,
        })),
      );
    }

    // 5. 保存系统账户算力
    if (result.systemContributions.length > 0) {
      await this.systemAccountRepository.ensureSystemAccountsExist();

      for (const sys of result.systemContributions) {
        await this.systemAccountRepository.addContribution(sys.accountType, sys.amount);
        await this.systemAccountRepository.saveContributionRecord({
          systemAccountType: sys.accountType,
          sourceAdoptionId,
          sourceAccountSequence,
          distributionRate: sys.rate.value.toNumber(),
          amount: sys.amount,
          effectiveDate,
          expireDate: null, // System account contributions never expire based on the schema's contributionNeverExpires field
        });
      }
    }
  }

  /**
   * 更新认种人的解锁状态
   */
  private async updateAdopterUnlockStatus(accountSequence: string): Promise<void> {
    const account = await this.contributionAccountRepository.findByAccountSequence(accountSequence);
    if (!account) return;

    if (!account.hasAdopted) {
      account.markAsAdopted();
      await this.contributionAccountRepository.save(account);
    }
  }

  /**
   * 更新上线的解锁状态（直推用户认种后）
   */
  private async updateReferrerUnlockStatus(referrerAccountSequence: string): Promise<void> {
    const account = await this.contributionAccountRepository.findByAccountSequence(referrerAccountSequence);
    if (!account) return;

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

    // 更新解锁状态
    const currentCount = account.directReferralAdoptedCount;
    if (directReferralAdoptedCount > currentCount) {
      // 需要增量更新
      for (let i = currentCount; i < directReferralAdoptedCount; i++) {
        account.incrementDirectReferralAdoptedCount();
      }
      await this.contributionAccountRepository.save(account);
      this.logger.debug(
        `Updated referrer ${referrerAccountSequence} unlock status: level=${account.unlockedLevelDepth}, bonus=${account.unlockedBonusTiers}`,
      );
    }
  }
}
