import { Injectable } from '@nestjs/common';
import Decimal from 'decimal.js';
import {
  ISyncedDataRepository,
  SyncedUser,
  SyncedAdoption,
  SyncedReferral,
} from '../../../domain/repositories/synced-data.repository.interface';
import { UnitOfWork, TransactionClient } from '../unit-of-work/unit-of-work';

@Injectable()
export class SyncedDataRepository implements ISyncedDataRepository {
  constructor(private readonly unitOfWork: UnitOfWork) {}

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

  // ========== User 操作 ==========

  async upsertSyncedUser(data: {
    accountSequence: string;
    originalUserId: bigint;
    phone?: string | null;
    status?: string | null;
    sourceSequenceNum: bigint;
  }): Promise<SyncedUser> {
    const record = await this.client.syncedUser.upsert({
      where: { accountSequence: data.accountSequence },
      create: {
        originalUserId: data.originalUserId,
        accountSequence: data.accountSequence,
        phone: data.phone ?? null,
        status: data.status ?? null,
        sourceSequenceNum: data.sourceSequenceNum,
        syncedAt: new Date(),
      },
      update: {
        phone: data.phone ?? undefined,
        status: data.status ?? undefined,
        sourceSequenceNum: data.sourceSequenceNum,
        syncedAt: new Date(),
      },
    });

    return this.toSyncedUser(record);
  }

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

    if (!record) {
      return null;
    }

    return this.toSyncedUser(record);
  }

  async findUncalculatedUsers(limit: number = 100): Promise<SyncedUser[]> {
    const records = await this.client.syncedUser.findMany({
      where: { contributionCalculated: false },
      orderBy: { createdAt: 'asc' },
      take: limit,
    });

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

  async markUserContributionCalculated(accountSequence: string, tx?: any): Promise<void> {
    const client = tx ?? this.client;
    await client.syncedUser.update({
      where: { accountSequence },
      data: {
        contributionCalculated: true,
        contributionCalculatedAt: new Date(),
      },
    });
  }

  // ========== Adoption 操作 ==========

  async upsertSyncedAdoption(data: {
    originalAdoptionId: bigint;
    accountSequence: string;
    treeCount: number;
    adoptionDate: Date;
    status?: string | null;
    selectedProvince?: string | null;
    selectedCity?: string | null;
    contributionPerTree: Decimal;
    sourceSequenceNum: bigint;
  }): Promise<SyncedAdoption> {
    const record = await this.client.syncedAdoption.upsert({
      where: { originalAdoptionId: data.originalAdoptionId },
      create: {
        originalAdoptionId: data.originalAdoptionId,
        accountSequence: data.accountSequence,
        treeCount: data.treeCount,
        adoptionDate: data.adoptionDate,
        status: data.status ?? null,
        selectedProvince: data.selectedProvince ?? null,
        selectedCity: data.selectedCity ?? null,
        contributionPerTree: data.contributionPerTree,
        sourceSequenceNum: data.sourceSequenceNum,
        syncedAt: new Date(),
      },
      update: {
        accountSequence: data.accountSequence,
        treeCount: data.treeCount,
        adoptionDate: data.adoptionDate,
        status: data.status ?? undefined,
        selectedProvince: data.selectedProvince ?? undefined,
        selectedCity: data.selectedCity ?? undefined,
        contributionPerTree: data.contributionPerTree,
        sourceSequenceNum: data.sourceSequenceNum,
        syncedAt: new Date(),
      },
    });

    return this.toSyncedAdoption(record);
  }

  async findSyncedAdoptionByOriginalId(originalAdoptionId: bigint): Promise<SyncedAdoption | null> {
    const record = await this.client.syncedAdoption.findUnique({
      where: { originalAdoptionId },
    });

    if (!record) {
      return null;
    }

    return this.toSyncedAdoption(record);
  }

  async findUndistributedAdoptions(limit: number = 100): Promise<SyncedAdoption[]> {
    const records = await this.client.syncedAdoption.findMany({
      where: {
        contributionDistributed: false,
        status: 'MINING_ENABLED', // 只处理最终成功的认种订单
      },
      orderBy: { adoptionDate: 'asc' },
      take: limit,
    });

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

  async findAdoptionsByAccountSequence(accountSequence: string): Promise<SyncedAdoption[]> {
    const records = await this.client.syncedAdoption.findMany({
      where: { accountSequence },
      orderBy: { adoptionDate: 'asc' },
    });

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

  async markAdoptionContributionDistributed(
    originalAdoptionId: bigint,
    distributionSummary?: string,
    tx?: any,
  ): Promise<void> {
    const client = tx ?? this.client;
    await client.syncedAdoption.update({
      where: { originalAdoptionId },
      data: {
        contributionDistributed: true,
        contributionDistributedAt: new Date(),
        distributionSummary: distributionSummary ?? null,
      },
    });
  }

  async getTotalTreesByAccountSequence(accountSequence: string): Promise<number> {
    const result = await this.client.syncedAdoption.aggregate({
      where: {
        accountSequence,
        status: 'MINING_ENABLED', // 只统计最终成功的认种订单
      },
      _sum: { treeCount: true },
    });
    return result._sum.treeCount ?? 0;
  }

  // ========== Referral 操作 ==========

  async upsertSyncedReferral(data: {
    accountSequence: string;
    referrerAccountSequence?: string | null;
    referrerUserId?: bigint | null;
    originalUserId?: bigint | null;
    ancestorPath?: string | null;
    depth?: number;
    sourceSequenceNum: bigint;
  }): Promise<SyncedReferral> {
    const record = await this.client.syncedReferral.upsert({
      where: { accountSequence: data.accountSequence },
      create: {
        accountSequence: data.accountSequence,
        referrerAccountSequence: data.referrerAccountSequence ?? null,
        referrerUserId: data.referrerUserId ?? null,
        originalUserId: data.originalUserId ?? null,
        ancestorPath: data.ancestorPath ?? null,
        depth: data.depth ?? 0,
        sourceSequenceNum: data.sourceSequenceNum,
        syncedAt: new Date(),
      },
      update: {
        referrerAccountSequence: data.referrerAccountSequence ?? undefined,
        referrerUserId: data.referrerUserId ?? undefined,
        originalUserId: data.originalUserId ?? undefined,
        ancestorPath: data.ancestorPath ?? undefined,
        depth: data.depth ?? undefined,
        sourceSequenceNum: data.sourceSequenceNum,
        syncedAt: new Date(),
      },
    });

    return this.toSyncedReferral(record);
  }

  async findSyncedReferralByOriginalUserId(originalUserId: bigint): Promise<SyncedReferral | null> {
    const record = await this.client.syncedReferral.findFirst({
      where: { originalUserId },
    });

    if (!record) {
      return null;
    }

    return this.toSyncedReferral(record);
  }

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

    if (!record) {
      return null;
    }

    return this.toSyncedReferral(record);
  }

  async findDirectReferrals(referrerAccountSequence: string): Promise<SyncedReferral[]> {
    const records = await this.client.syncedReferral.findMany({
      where: { referrerAccountSequence },
      orderBy: { createdAt: 'asc' },
    });

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

  async findAncestorChain(accountSequence: string, maxLevel: number = 15): Promise<SyncedReferral[]> {
    const ancestors: SyncedReferral[] = [];
    let currentSequence = accountSequence;

    for (let i = 0; i < maxLevel; i++) {
      // 获取当前账户的 referral 记录（包含该账户作为上线的信息）
      const referral = await this.findSyncedReferralByAccountSequence(currentSequence);
      if (!referral) {
        break;
      }

      // 把当前账户加入上线链条
      ancestors.push(referral);

      // 如果没有更上级的推荐人，终止
      if (!referral.referrerAccountSequence) {
        break;
      }

      // 继续向上追溯
      currentSequence = referral.referrerAccountSequence;
    }

    return ancestors;
  }

  async getDirectReferralAdoptedCount(referrerAccountSequence: string): Promise<number> {
    const directReferrals = await this.client.syncedReferral.findMany({
      where: { referrerAccountSequence },
      select: { accountSequence: true },
    });

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

    const accountSequences = directReferrals.map((r) => r.accountSequence);

    // 解锁阈值按「人头」计：常规认种和预种均以「该直推用户是否有任意一条
    // MINING_ENABLED 记录」为准，每人算 1，不论认种了几棵树或几份预种。
    // 预种 handler 会在用户首次付款时向 synced_adoptions 插入一条
    // treeCount=0、status=MINING_ENABLED 的 marker，确保预种用户也能被计入。
    const adoptedCount = await this.client.syncedAdoption.findMany({
      where: {
        accountSequence: { in: accountSequences },
        status: 'MINING_ENABLED',
      },
      distinct: ['accountSequence'],
    });

    return adoptedCount.length;
  }

  async getTeamTreesByLevel(
    accountSequence: string,
    maxLevel: number = 15,
  ): Promise<Map<number, number>> {
    const result = new Map<number, number>();

    for (let level = 1; level <= maxLevel; level++) {
      result.set(level, 0);
    }

    const processLevel = async (sequences: string[], currentLevel: number): Promise<void> => {
      if (currentLevel > maxLevel || sequences.length === 0) return;

      const adoptions = await this.client.syncedAdoption.groupBy({
        by: ['accountSequence'],
        where: {
          accountSequence: { in: sequences },
          status: 'MINING_ENABLED', // 只统计最终成功的认种订单
        },
        _sum: { treeCount: true },
      });

      let levelTrees = 0;
      for (const adoption of adoptions) {
        levelTrees += adoption._sum.treeCount ?? 0;
      }
      result.set(currentLevel, levelTrees);

      const nextLevelReferrals = await this.client.syncedReferral.findMany({
        where: { referrerAccountSequence: { in: sequences } },
        select: { accountSequence: true },
      });

      if (nextLevelReferrals.length > 0) {
        await processLevel(
          nextLevelReferrals.map((r) => r.accountSequence),
          currentLevel + 1,
        );
      }
    };

    const directReferrals = await this.client.syncedReferral.findMany({
      where: { referrerAccountSequence: accountSequence },
      select: { accountSequence: true },
    });

    if (directReferrals.length > 0) {
      await processLevel(
        directReferrals.map((r) => r.accountSequence),
        1,
      );
    }

    return result;
  }

  // ========== 认种分类账查询 ==========

  async getPlantingLedger(
    accountSequence: string,
    page: number = 1,
    pageSize: number = 20,
  ): Promise<{
    items: SyncedAdoption[];
    total: number;
    page: number;
    pageSize: number;
    totalPages: number;
  }> {
    const skip = (page - 1) * pageSize;
    // 只返回 MINING_ENABLED 状态的认种记录
    const whereClause = { accountSequence, status: 'MINING_ENABLED' };

    const [items, total] = await Promise.all([
      this.client.syncedAdoption.findMany({
        where: whereClause,
        orderBy: { adoptionDate: 'desc' },
        skip,
        take: pageSize,
      }),
      this.client.syncedAdoption.count({
        where: whereClause,
      }),
    ]);

    return {
      items: items.map((r) => this.toSyncedAdoption(r)),
      total,
      page,
      pageSize,
      totalPages: Math.ceil(total / pageSize),
    };
  }

  async getPlantingSummary(accountSequence: string): Promise<{
    totalOrders: number;
    totalTreeCount: number;
    totalAmount: string;
    effectiveTreeCount: number;
    firstPlantingAt: Date | null;
    lastPlantingAt: Date | null;
  }> {
    // 只统计 MINING_ENABLED 状态的认种记录
    const adoptions = await this.client.syncedAdoption.findMany({
      where: { accountSequence, status: 'MINING_ENABLED' },
      orderBy: { adoptionDate: 'asc' },
    });

    if (adoptions.length === 0) {
      return {
        totalOrders: 0,
        totalTreeCount: 0,
        totalAmount: '0',
        effectiveTreeCount: 0,
        firstPlantingAt: null,
        lastPlantingAt: null,
      };
    }

    const totalOrders = adoptions.length;
    const totalTreeCount = adoptions.reduce((sum, a) => sum + a.treeCount, 0);

    // 计算总金额：treeCount * contributionPerTree
    let totalAmount = new Decimal(0);
    for (const adoption of adoptions) {
      const amount = new Decimal(adoption.contributionPerTree).mul(adoption.treeCount);
      totalAmount = totalAmount.add(amount);
    }

    return {
      totalOrders,
      totalTreeCount,
      totalAmount: totalAmount.toString(),
      effectiveTreeCount: totalTreeCount, // 全部都是有效的 MINING_ENABLED
      firstPlantingAt: adoptions[0]?.adoptionDate || null,
      lastPlantingAt: adoptions[adoptions.length - 1]?.adoptionDate || null,
    };
  }

  // ========== 统计方法（用于查询服务）==========

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

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

  async countUndistributedAdoptions(): Promise<number> {
    return this.client.syncedAdoption.count({
      where: {
        contributionDistributed: false,
        status: 'MINING_ENABLED', // 只统计最终成功的认种订单
      },
    });
  }

  async getTotalTrees(): Promise<number> {
    const result = await this.client.syncedAdoption.aggregate({
      where: {
        status: 'MINING_ENABLED', // 只统计最终成功的认种订单
      },
      _sum: { treeCount: true },
    });
    return result._sum.treeCount ?? 0;
  }

  // ========== 私有方法 ==========

  private toSyncedUser(record: any): SyncedUser {
    return {
      id: record.id,
      accountSequence: record.accountSequence,
      originalUserId: record.originalUserId,
      phone: record.phone,
      status: record.status,
      sourceSequenceNum: record.sourceSequenceNum,
      syncedAt: record.syncedAt,
      contributionCalculated: record.contributionCalculated,
      contributionCalculatedAt: record.contributionCalculatedAt,
      createdAt: record.createdAt,
    };
  }

  private toSyncedAdoption(record: any): SyncedAdoption {
    return {
      id: record.id,
      originalAdoptionId: record.originalAdoptionId,
      accountSequence: record.accountSequence,
      treeCount: record.treeCount,
      adoptionDate: record.adoptionDate,
      status: record.status,
      selectedProvince: record.selectedProvince,
      selectedCity: record.selectedCity,
      contributionPerTree: record.contributionPerTree,
      sourceSequenceNum: record.sourceSequenceNum,
      syncedAt: record.syncedAt,
      contributionDistributed: record.contributionDistributed,
      contributionDistributedAt: record.contributionDistributedAt,
      createdAt: record.createdAt,
    };
  }

  private toSyncedReferral(record: any): SyncedReferral {
    return {
      id: record.id,
      accountSequence: record.accountSequence,
      referrerAccountSequence: record.referrerAccountSequence,
      referrerUserId: record.referrerUserId,
      originalUserId: record.originalUserId,
      ancestorPath: record.ancestorPath,
      depth: record.depth,
      sourceSequenceNum: record.sourceSequenceNum,
      syncedAt: record.syncedAt,
      createdAt: record.createdAt,
    };
  }
}
