import { Injectable } from '@nestjs/common';
import { Decimal } from 'decimal.js';
import { IContributionAccountRepository } from '../../../domain/repositories/contribution-account.repository.interface';
import { ContributionAccountAggregate, ContributionSourceType } from '../../../domain/aggregates/contribution-account.aggregate';
import { ContributionAmount } from '../../../domain/value-objects/contribution-amount.vo';
import { UnitOfWork, TransactionClient } from '../unit-of-work/unit-of-work';

@Injectable()
export class ContributionAccountRepository implements IContributionAccountRepository {
  constructor(private readonly unitOfWork: UnitOfWork) {}

  private get client(): TransactionClient {
    return this.unitOfWork.getClient();
  }

  async findByAccountSequence(accountSequence: string): Promise<ContributionAccountAggregate | null> {
    const record = await this.client.contributionAccount.findUnique({
      where: { accountSequence },
    });

    if (!record) {
      return null;
    }

    return this.toDomain(record);
  }

  async findByAccountSequenceForUpdate(
    accountSequence: string,
    tx?: any,
  ): Promise<ContributionAccountAggregate | null> {
    const client = tx ?? this.client;
    // In Prisma, we use a raw query with FOR UPDATE or rely on transaction isolation
    // For now, we'll use a regular findUnique within the transaction context
    const record = await client.contributionAccount.findUnique({
      where: { accountSequence },
    });

    if (!record) {
      return null;
    }

    return this.toDomain(record);
  }

  async findByAccountSequences(accountSequences: string[]): Promise<Map<string, ContributionAccountAggregate>> {
    const records = await this.client.contributionAccount.findMany({
      where: { accountSequence: { in: accountSequences } },
    });

    const result = new Map<string, ContributionAccountAggregate>();
    for (const record of records) {
      result.set(record.accountSequence, this.toDomain(record));
    }

    return result;
  }

  async save(aggregate: ContributionAccountAggregate, tx?: any): Promise<ContributionAccountAggregate> {
    const client = tx ?? this.client;
    const data = this.toPersistence(aggregate);

    const result = await client.contributionAccount.upsert({
      where: { accountSequence: aggregate.accountSequence },
      create: data,
      update: data,
    });

    return this.toDomain(result);
  }

  async saveMany(aggregates: ContributionAccountAggregate[], tx?: any): Promise<void> {
    for (const aggregate of aggregates) {
      await this.save(aggregate, tx);
    }
  }

  async updateContribution(
    accountSequence: string,
    sourceType: ContributionSourceType,
    amount: ContributionAmount,
    levelDepth?: number | null,
    bonusTier?: number | null,
  ): Promise<void> {
    // 个人算力直接增加到 personalContribution 和 effectiveContribution
    if (sourceType === ContributionSourceType.PERSONAL) {
      await this.client.contributionAccount.update({
        where: { accountSequence },
        data: {
          personalContribution: { increment: amount.value },
          effectiveContribution: { increment: amount.value },
          updatedAt: new Date(),
        },
      });
    } else if (sourceType === ContributionSourceType.TEAM_LEVEL && levelDepth) {
      // 层级算力：更新对应层级的 pending 字段和汇总字段
      const levelPendingField = `level${levelDepth}Pending` as const;
      await this.client.contributionAccount.update({
        where: { accountSequence },
        data: {
          [levelPendingField]: { increment: amount.value },
          totalLevelPending: { increment: amount.value },
          totalPending: { increment: amount.value },
          effectiveContribution: { increment: amount.value },
          updatedAt: new Date(),
        },
      });
    } else if (sourceType === ContributionSourceType.TEAM_BONUS && bonusTier) {
      // 加成算力：更新对应档位的 pending 字段和汇总字段
      const bonusTierField = `bonusTier${bonusTier}Pending` as const;
      await this.client.contributionAccount.update({
        where: { accountSequence },
        data: {
          [bonusTierField]: { increment: amount.value },
          totalBonusPending: { increment: amount.value },
          totalPending: { increment: amount.value },
          effectiveContribution: { increment: amount.value },
          updatedAt: new Date(),
        },
      });
    } else {
      // 兜底：只更新 effectiveContribution
      await this.client.contributionAccount.update({
        where: { accountSequence },
        data: {
          effectiveContribution: { increment: amount.value },
          updatedAt: new Date(),
        },
      });
    }
  }

  async findAllWithPagination(page: number, pageSize: number): Promise<{
    data: ContributionAccountAggregate[];
    total: number;
  }> {
    const [records, total] = await Promise.all([
      this.client.contributionAccount.findMany({
        skip: (page - 1) * pageSize,
        take: pageSize,
        orderBy: { effectiveContribution: 'desc' },
      }),
      this.client.contributionAccount.count(),
    ]);

    return {
      data: records.map((r) => this.toDomain(r)),
      total,
    };
  }

  async findMany(options: {
    page?: number;
    limit?: number;
    orderBy?: 'effectiveContribution' | 'personalContribution';
    order?: 'asc' | 'desc';
  }): Promise<{
    items: ContributionAccountAggregate[];
    total: number;
  }> {
    const page = options.page ?? 1;
    const limit = options.limit ?? 50;
    const orderBy = options.orderBy ?? 'effectiveContribution';
    const order = options.order ?? 'desc';

    const [records, total] = await Promise.all([
      this.client.contributionAccount.findMany({
        skip: (page - 1) * limit,
        take: limit,
        orderBy: { [orderBy]: order },
      }),
      this.client.contributionAccount.count(),
    ]);

    return {
      items: records.map((r) => this.toDomain(r)),
      total,
    };
  }

  async findAllWithEffectiveContribution(): Promise<ContributionAccountAggregate[]> {
    const records = await this.client.contributionAccount.findMany({
      where: { effectiveContribution: { gt: 0 } },
      orderBy: { effectiveContribution: 'desc' },
    });

    return records.map((r) => this.toDomain(r));
  }

  async getNetworkTotalEffectiveContribution(): Promise<string> {
    const result = await this.client.contributionAccount.aggregate({
      _sum: { effectiveContribution: true },
    });

    return (result._sum.effectiveContribution || new Decimal(0)).toString();
  }

  async findTopContributors(limit: number): Promise<ContributionAccountAggregate[]> {
    const records = await this.client.contributionAccount.findMany({
      where: { effectiveContribution: { gt: 0 } },
      orderBy: { effectiveContribution: 'desc' },
      take: limit,
    });

    return records.map((r) => this.toDomain(r));
  }

  async getTotalContribution(): Promise<ContributionAmount> {
    const result = await this.client.contributionAccount.aggregate({
      _sum: { effectiveContribution: true },
    });

    return new ContributionAmount(result._sum.effectiveContribution || 0);
  }

  async countAccounts(): Promise<number> {
    return this.client.contributionAccount.count();
  }

  async countAccountsWithContribution(): Promise<number> {
    return this.client.contributionAccount.count({
      where: { effectiveContribution: { gt: 0 } },
    });
  }

  async findRecentlyUpdated(since: Date, limit: number = 500): Promise<ContributionAccountAggregate[]> {
    const records = await this.client.contributionAccount.findMany({
      where: { updatedAt: { gte: since } },
      orderBy: { updatedAt: 'desc' },
      take: limit,
    });

    return records.map((r) => this.toDomain(r));
  }

  /**
   * 查找解锁状态不完整的账户
   * 用于定时任务补发奖励
   * @param limit 返回的最大数量
   * @returns 解锁状态不完整的账户列表
   */
  /**
   * 查找所有解锁状态不完整的账户，用于 processContributionBackfill 定时补发任务。
   *
   * 满足以下任一条件的账户视为"不完整"：
   *   - unlockedLevelDepth < 15：层级算力尚未解锁到第15级（需要直推认种用户数达到5个才能满解锁）
   *   - unlockedBonusTiers < 3：奖励档位尚未全部解锁（需要直推认种用户数达到4个才能满解锁）
   *
   * 注意事项：
   *   - 不设数量上限（无 LIMIT），确保每次定时任务都能处理全量账户，避免因账户排序靠后而永久跳过。
   *   - 原因：此前限制 100 条 + 按 updatedAt ASC 排序，导致最近更新的账户（如预种用户）因排在第
   *     100 名之后，永远无法被处理（饥饿问题 / starvation）。
   *   - 当账户量增长到数万级别时，可考虑改为游标分页（cursor-based pagination）逐批处理，
   *     以控制单次 cron 任务的执行时长。当前规模（约 100-500 个账户）无性能压力。
   */
  async findAccountsWithIncompleteUnlock(): Promise<ContributionAccountAggregate[]> {
    const records = await this.client.contributionAccount.findMany({
      where: {
        hasAdopted: true,
        OR: [
          { unlockedLevelDepth: { lt: 15 } },
          { unlockedBonusTiers: { lt: 3 } },
        ],
      },
    });

    return records.map((r) => this.toDomain(r));
  }

  /**
   * 获取详细算力汇总（按类型分解）
   */
  async getDetailedContributionStats(): Promise<{
    // 个人算力总计
    personalTotal: string;
    // 层级算力 - 已解锁（已分配给上线）
    levelUnlocked: string;
    // 层级算力 - 未解锁（待解锁的pending）
    levelPending: string;
    // 层级按档位分解
    levelByTier: {
      tier1: { unlocked: string; pending: string }; // 1-5级
      tier2: { unlocked: string; pending: string }; // 6-10级
      tier3: { unlocked: string; pending: string }; // 11-15级
    };
    // 团队奖励算力 - 已解锁
    bonusUnlocked: string;
    // 团队奖励算力 - 未解锁
    bonusPending: string;
    // 团队奖励按档位分解
    bonusByTier: {
      tier1: { unlocked: string; pending: string };
      tier2: { unlocked: string; pending: string };
      tier3: { unlocked: string; pending: string };
    };
  }> {
    const result = await this.client.contributionAccount.aggregate({
      _sum: {
        personalContribution: true,
        // 层级 1-5
        level1Pending: true,
        level2Pending: true,
        level3Pending: true,
        level4Pending: true,
        level5Pending: true,
        // 层级 6-10
        level6Pending: true,
        level7Pending: true,
        level8Pending: true,
        level9Pending: true,
        level10Pending: true,
        // 层级 11-15
        level11Pending: true,
        level12Pending: true,
        level13Pending: true,
        level14Pending: true,
        level15Pending: true,
        // 团队奖励
        bonusTier1Pending: true,
        bonusTier2Pending: true,
        bonusTier3Pending: true,
        // 汇总
        totalLevelPending: true,
        totalBonusPending: true,
        totalUnlocked: true,
      },
    });

    const sum = result._sum;

    // 层级 1-5 已解锁（在pending字段中存储的是已分配给该用户的层级算力）
    const level1to5 = new Decimal(sum.level1Pending || 0)
      .plus(sum.level2Pending || 0)
      .plus(sum.level3Pending || 0)
      .plus(sum.level4Pending || 0)
      .plus(sum.level5Pending || 0);

    // 层级 6-10
    const level6to10 = new Decimal(sum.level6Pending || 0)
      .plus(sum.level7Pending || 0)
      .plus(sum.level8Pending || 0)
      .plus(sum.level9Pending || 0)
      .plus(sum.level10Pending || 0);

    // 层级 11-15
    const level11to15 = new Decimal(sum.level11Pending || 0)
      .plus(sum.level12Pending || 0)
      .plus(sum.level13Pending || 0)
      .plus(sum.level14Pending || 0)
      .plus(sum.level15Pending || 0);

    return {
      personalTotal: (sum.personalContribution || new Decimal(0)).toString(),
      levelUnlocked: (sum.totalLevelPending || new Decimal(0)).toString(),
      levelPending: '0', // 未解锁的存储在 unallocated 表中
      levelByTier: {
        tier1: { unlocked: level1to5.toString(), pending: '0' },
        tier2: { unlocked: level6to10.toString(), pending: '0' },
        tier3: { unlocked: level11to15.toString(), pending: '0' },
      },
      bonusUnlocked: (sum.totalBonusPending || new Decimal(0)).toString(),
      bonusPending: '0', // 未解锁的存储在 unallocated 表中
      bonusByTier: {
        tier1: { unlocked: (sum.bonusTier1Pending || new Decimal(0)).toString(), pending: '0' },
        tier2: { unlocked: (sum.bonusTier2Pending || new Decimal(0)).toString(), pending: '0' },
        tier3: { unlocked: (sum.bonusTier3Pending || new Decimal(0)).toString(), pending: '0' },
      },
    };
  }

  private toDomain(record: any): ContributionAccountAggregate {
    return ContributionAccountAggregate.fromPersistence({
      id: record.id,
      accountSequence: record.accountSequence,
      personalContribution: record.personalContribution,
      // 18 个待解锁字段
      level1Pending: record.level1Pending,
      level2Pending: record.level2Pending,
      level3Pending: record.level3Pending,
      level4Pending: record.level4Pending,
      level5Pending: record.level5Pending,
      level6Pending: record.level6Pending,
      level7Pending: record.level7Pending,
      level8Pending: record.level8Pending,
      level9Pending: record.level9Pending,
      level10Pending: record.level10Pending,
      level11Pending: record.level11Pending,
      level12Pending: record.level12Pending,
      level13Pending: record.level13Pending,
      level14Pending: record.level14Pending,
      level15Pending: record.level15Pending,
      bonusTier1Pending: record.bonusTier1Pending,
      bonusTier2Pending: record.bonusTier2Pending,
      bonusTier3Pending: record.bonusTier3Pending,
      // 汇总字段
      totalLevelPending: record.totalLevelPending,
      totalBonusPending: record.totalBonusPending,
      totalPending: record.totalPending,
      totalUnlocked: record.totalUnlocked,
      effectiveContribution: record.effectiveContribution,
      // 解锁状态
      hasAdopted: record.hasAdopted,
      directReferralAdoptedCount: record.directReferralAdoptedCount,
      unlockedLevelDepth: record.unlockedLevelDepth,
      unlockedBonusTiers: record.unlockedBonusTiers,
      version: record.version,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
    });
  }

  private toPersistence(aggregate: ContributionAccountAggregate): any {
    return aggregate.toPersistence();
  }
}
