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 { ContributionRecordAggregate } from '../../domain/aggregates/contribution-record.aggregate';
import { ContributionAmount } from '../../domain/value-objects/contribution-amount.vo';
import { SyncedReferral } from '../../domain/repositories/synced-data.repository.interface';
import { ContributionDistributionPublisherService } from './contribution-distribution-publisher.service';
import { ContributionRateService } from './contribution-rate.service';
import { BonusClaimService } from './bonus-claim.service';
import { ContributionRecordSyncedEvent, NetworkProgressUpdatedEvent, ContributionAccountUpdatedEvent, SystemAccountSyncedEvent, SystemContributionRecordCreatedEvent, UnallocatedContributionSyncedEvent } from '../../domain/events';

/**
 * 算力计算应用服务
 * 协调领域服务和仓库，完成算力计算的完整流程
 */
@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,
    private readonly distributionPublisher: ContributionDistributionPublisherService,
    private readonly contributionRateService: ContributionRateService,
    private readonly bonusClaimService: BonusClaimService,
  ) {}

  /**
   * 为认种计算并分配算力
   */
  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);

    // 推荐数据未同步时跳过（不标记 distributed，调度器下次重试）
    if (!userReferral) {
      this.logger.warn(
        `[Referral-Guard] Deferring adoption ${originalAdoptionId}: ` +
          `referral for ${adoption.accountSequence} not yet synced, will retry on next scheduler tick`,
      );
      return;
    }

    this.logger.debug(
      `[Referral-Guard] Referral found for ${adoption.accountSequence}: ` +
        `referrer=${userReferral.referrerAccountSequence || 'NONE (root)'}`,
    );

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

    // 获取认种人的算力账户（用于判断 TEAM_BONUS 解锁状态）
    const adopterAccount = await this.contributionAccountRepository.findByAccountSequence(adoption.accountSequence);

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

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

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

      // 构建分配摘要
      const distributionSummary = this.buildDistributionSummary(adoption, result);

      // 标记认种已处理，同时保存分配摘要
      await this.syncedDataRepository.markAdoptionContributionDistributed(
        adoption.originalAdoptionId,
        JSON.stringify(distributionSummary),
      );

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

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

      // 发布分配结果到 Kafka（通过 Outbox 模式）
      // 使用认种订单选择的省市代码
      const provinceCode = adoption.selectedProvince ?? 'DEFAULT';
      const cityCode = adoption.selectedCity ?? 'DEFAULT';
      await this.distributionPublisher.publishDistributionResult(
        adoption,
        result,
        provinceCode,
        cityCode,
      );
    });

    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}`,
    );

    // 更新全网认种进度（更新 NetworkAdoptionProgress 表）
    // 判断是否为新认种用户：之前没有账户记录即为新用户
    const isNewUser = !adopterAccount;
    await this.contributionRateService.updateNetworkProgress(
      adoption.treeCount,
      adoption.adoptionDate,
      adoption.originalAdoptionId,
      isNewUser,
    );

    // 发布全网进度更新事件（用于 mining-service 同步全网理论算力）
    await this.publishNetworkProgressEvent();
  }

  /**
   * 发布全网进度更新事件
   */
  private async publishNetworkProgressEvent(): Promise<void> {
    try {
      const progress = await this.contributionRateService.getNetworkProgress();

      const event = new NetworkProgressUpdatedEvent(
        progress.totalTreeCount,
        progress.totalAdoptionOrders,
        progress.totalAdoptedUsers,
        progress.currentUnit,
        progress.currentMultiplier.toString(),
        progress.currentContributionPerTree.toString(),
        progress.nextUnitTreeCount,
      );

      await this.outboxRepository.save({
        aggregateType: NetworkProgressUpdatedEvent.AGGREGATE_TYPE,
        aggregateId: 'network',
        eventType: NetworkProgressUpdatedEvent.EVENT_TYPE,
        payload: event.toPayload(),
      });

      this.logger.debug(`Published NetworkProgressUpdatedEvent: trees=${progress.totalTreeCount}`);
    } catch (error) {
      this.logger.error('Failed to publish NetworkProgressUpdatedEvent', error);
    }
  }

  /**
   * 批量计算未处理的认种
   */
  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> {
    // 收集所有保存后的记录（带ID）用于发布事件
    const savedRecords: ContributionRecordAggregate[] = [];
    // 收集所有被更新的账户序列号（用于发布账户更新事件）
    const updatedAccountSequences = new Set<string>();

    // 1. 保存个人算力记录
    const savedPersonalRecord = await this.contributionRecordRepository.save(result.personalRecord);
    savedRecords.push(savedPersonalRecord);

    // 更新个人算力账户
    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);
    updatedAccountSequences.add(result.personalRecord.accountSequence);

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

      // 更新各上线的算力账户
      for (const record of result.teamLevelRecords) {
        await this.contributionAccountRepository.updateContribution(
          record.accountSequence,
          ContributionSourceType.TEAM_LEVEL,
          record.amount,
          record.levelDepth,  // 传递层级深度
          null,
        );
        updatedAccountSequences.add(record.accountSequence);
      }
    }

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

      // 更新直接上线的算力账户
      for (const record of result.teamBonusRecords) {
        await this.contributionAccountRepository.updateContribution(
          record.accountSequence,
          ContributionSourceType.TEAM_BONUS,
          record.amount,
          null,
          record.bonusTier,  // 传递加成档位
        );
        updatedAccountSequences.add(record.accountSequence);
      }
    }

    // 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,
        })),
      );

      // 汇总未分配算力到 HEADQUARTERS（总部账户）
      const totalUnallocatedAmount = result.unallocatedContributions.reduce(
        (sum, u) => sum.add(u.amount),
        new ContributionAmount(0),
      );
      await this.systemAccountRepository.addContribution(
        'HEADQUARTERS',
        null,
        totalUnallocatedAmount,
      );

      // 为每笔未分配算力创建 HEADQUARTERS 明细记录
      for (const unallocated of result.unallocatedContributions) {
        // 确定来源类型和层级深度
        const sourceType = unallocated.type as string; // LEVEL_OVERFLOW / LEVEL_NO_ANCESTOR / BONUS_TIER_1/2/3
        const levelDepth = unallocated.levelDepth;

        const savedRecord = await this.systemAccountRepository.saveContributionRecord({
          accountType: 'HEADQUARTERS',
          regionCode: null,
          sourceAdoptionId,
          sourceAccountSequence,
          sourceType,
          levelDepth,
          distributionRate: 0, // 未分配算力没有固定比例
          amount: unallocated.amount,
          effectiveDate,
          expireDate: null,
        });

        // 发布 HEADQUARTERS 算力明细事件
        const recordEvent = new SystemContributionRecordCreatedEvent(
          savedRecord.id,
          'HEADQUARTERS',
          null,
          sourceAdoptionId,
          sourceAccountSequence,
          sourceType as any,
          levelDepth,
          0,
          unallocated.amount.value.toString(),
          effectiveDate,
          null,
          savedRecord.createdAt,
        );
        await this.outboxRepository.save({
          aggregateType: SystemContributionRecordCreatedEvent.AGGREGATE_TYPE,
          aggregateId: savedRecord.id.toString(),
          eventType: SystemContributionRecordCreatedEvent.EVENT_TYPE,
          payload: recordEvent.toPayload(),
        });
      }

      // 发布 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(),
        });
      }

      // 发布未分配算力同步事件（用于 mining-service 同步待解锁算力）
      for (const unallocated of result.unallocatedContributions) {
        const event = new UnallocatedContributionSyncedEvent(
          sourceAdoptionId,
          sourceAccountSequence,
          unallocated.wouldBeAccountSequence,
          unallocated.type,
          unallocated.amount.value.toString(),
          unallocated.reason,
          effectiveDate,
          expireDate,
        );
        await this.outboxRepository.save({
          aggregateType: UnallocatedContributionSyncedEvent.AGGREGATE_TYPE,
          aggregateId: `${sourceAdoptionId}-${unallocated.type}`,
          eventType: UnallocatedContributionSyncedEvent.EVENT_TYPE,
          payload: event.toPayload(),
        });
      }
    }

    // 5. 保存系统账户算力并发布同步事件
    if (result.systemContributions.length > 0) {
      await this.systemAccountRepository.ensureSystemAccountsExist();

      for (const sys of result.systemContributions) {
        // 动态创建/更新系统账户
        await this.systemAccountRepository.addContribution(
          sys.accountType,
          sys.regionCode,
          sys.amount,
        );

        // 保存算力明细记录
        const savedRecord = await this.systemAccountRepository.saveContributionRecord({
          accountType: sys.accountType,
          regionCode: sys.regionCode,
          sourceAdoptionId,
          sourceAccountSequence,
          sourceType: 'FIXED_RATE',  // 固定比例分配
          levelDepth: null,
          distributionRate: sys.rate.value.toNumber(),
          amount: sys.amount,
          effectiveDate,
          expireDate: null,
        });

        // 发布系统账户同步事件（用于 mining-service 同步系统账户算力）
        const systemAccount = await this.systemAccountRepository.findByTypeAndRegion(
          sys.accountType,
          sys.regionCode,
        );
        if (systemAccount) {
          const event = new SystemAccountSyncedEvent(
            sys.accountType,
            sys.regionCode,
            systemAccount.name,
            systemAccount.contributionBalance.value.toString(),
            systemAccount.createdAt,
          );
          await this.outboxRepository.save({
            aggregateType: SystemAccountSyncedEvent.AGGREGATE_TYPE,
            aggregateId: `${sys.accountType}:${sys.regionCode || 'null'}`,
            eventType: SystemAccountSyncedEvent.EVENT_TYPE,
            payload: event.toPayload(),
          });

          // 发布系统账户算力明细事件（用于 mining-admin-service 同步明细记录）
          const recordEvent = new SystemContributionRecordCreatedEvent(
            savedRecord.id,
            sys.accountType,
            sys.regionCode,  // 传递区域代码
            sourceAdoptionId,
            sourceAccountSequence,
            'FIXED_RATE',    // 固定比例分配
            null,            // 无层级深度
            sys.rate.value.toNumber(),
            sys.amount.value.toString(),
            effectiveDate,
            null,
            savedRecord.createdAt,
          );
          await this.outboxRepository.save({
            aggregateType: SystemContributionRecordCreatedEvent.AGGREGATE_TYPE,
            aggregateId: savedRecord.id.toString(),
            eventType: SystemContributionRecordCreatedEvent.EVENT_TYPE,
            payload: recordEvent.toPayload(),
          });
        }
      }
    }

    // 6. 发布算力记录同步事件（用于 mining-admin-service）- 使用保存后带 ID 的记录
    await this.publishContributionRecordEvents(savedRecords);

    // 7. 发布所有被更新账户的事件（用于 CDC 同步到 mining-admin-service）
    await this.publishUpdatedAccountEvents(updatedAccountSequences);
  }

  /**
   * 发布被更新账户的事件
   */
  private async publishUpdatedAccountEvents(accountSequences: Set<string>): Promise<void> {
    if (accountSequences.size === 0) return;

    for (const accountSequence of accountSequences) {
      const account = await this.contributionAccountRepository.findByAccountSequence(accountSequence);
      if (account) {
        await this.publishContributionAccountUpdatedEvent(account);
      }
    }
  }

  /**
   * 发布算力记录同步事件
   */
  private async publishContributionRecordEvents(
    savedRecords: ContributionRecordAggregate[],
  ): Promise<void> {
    if (savedRecords.length === 0) return;

    const events = savedRecords.map((record) => {
      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,
      );

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

    await this.outboxRepository.saveMany(events);
  }

  /**
   * 更新认种人的解锁状态
   */
  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);

      // 发布账户更新事件到 outbox（用于 CDC 同步到 mining-admin-service）
      await this.publishContributionAccountUpdatedEvent(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 previousCount = account.directReferralAdoptedCount;
    if (directReferralAdoptedCount > previousCount) {
      // 需要增量更新
      for (let i = previousCount; i < directReferralAdoptedCount; i++) {
        account.incrementDirectReferralAdoptedCount();
      }
      await this.contributionAccountRepository.save(account);

      // 发布账户更新事件到 outbox（用于 CDC 同步到 mining-admin-service）
      await this.publishContributionAccountUpdatedEvent(account);

      this.logger.debug(
        `Updated referrer ${referrerAccountSequence} unlock status: level=${account.unlockedLevelDepth}, bonus=${account.unlockedBonusTiers}`,
      );

      // 检查并处理奖励补发（T2: 直推≥2人, T3: 直推≥4人）
      await this.bonusClaimService.checkAndClaimBonus(
        referrerAccountSequence,
        previousCount,
        directReferralAdoptedCount,
      );
    }
  }

  /**
   * 构建分配摘要
   */
  private buildDistributionSummary(
    adoption: { treeCount: number; contributionPerTree: { toString: () => string } },
    result: ContributionDistributionResult,
  ): object {
    const totalContribution = adoption.treeCount * Number(adoption.contributionPerTree.toString());

    // 计算团队分配的实际金额
    let teamDistributed = 0;
    let teamUnallocated = 0;

    // TEAM_LEVEL 分配
    for (const record of result.teamLevelRecords) {
      teamDistributed += Number(record.amount.value.toString());
    }

    // TEAM_BONUS 分配
    for (const record of result.teamBonusRecords) {
      teamDistributed += Number(record.amount.value.toString());
    }

    // 未分配的团队算力（归总部）
    for (const unalloc of result.unallocatedContributions) {
      teamUnallocated += Number(unalloc.amount.value.toString());
    }

    // 系统账户分配
    const operationAmount = result.systemContributions.find(s => s.accountType === 'OPERATION')?.amount.value.toString() || '0';
    const provinceAmount = result.systemContributions.find(s => s.accountType === 'PROVINCE')?.amount.value.toString() || '0';
    const cityAmount = result.systemContributions.find(s => s.accountType === 'CITY')?.amount.value.toString() || '0';

    return {
      totalContribution: totalContribution.toFixed(4),
      personal: {
        rate: 0.70,
        amount: result.personalRecord.amount.value.toString(),
        label: '认种人账户',
      },
      operation: {
        rate: 0.12,
        amount: operationAmount,
        label: '运营账户',
      },
      province: {
        rate: 0.01,
        amount: provinceAmount,
        label: '省公司账户',
      },
      city: {
        rate: 0.02,
        amount: cityAmount,
        label: '市公司账户',
      },
      team: {
        rate: 0.15,
        amount: (totalContribution * 0.15).toFixed(4),
        distributed: teamDistributed.toFixed(4),
        unallocated: teamUnallocated.toFixed(4),
        label: '团队分配',
      },
    };
  }

  /**
   * 发布贡献值账户更新事件（用于 CDC 同步到 mining-admin-service）
   */
  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(),
    });

    this.logger.debug(
      `Published ContributionAccountUpdatedEvent for ${account.accountSequence}: ` +
        `directReferralAdoptedCount=${account.directReferralAdoptedCount}, ` +
        `hasAdopted=${account.hasAdopted}`,
    );
  }
}
