import { Injectable } from '@nestjs/common';
import { PrismaService } from '../database/prisma.service';
import {
  IReferralRelationshipRepository,
  ReferralRelationship,
  ReferralRelationshipProps,
} from '../../domain';

@Injectable()
export class ReferralRelationshipRepository implements IReferralRelationshipRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(relationship: ReferralRelationship): Promise<ReferralRelationship> {
    const data = relationship.toPersistence();

    const saved = await this.prisma.referralRelationship.upsert({
      where: { userId: data.userId },
      update: {
        referrerId: data.referrerId,
        myReferralCode: data.referralCode,
        ancestorPath: data.referralChain,
        depth: data.referralChain.length,
        updatedAt: new Date(),
      },
      create: {
        userId: data.userId,
        accountSequence: data.accountSequence,
        referrerId: data.referrerId,
        myReferralCode: data.referralCode,
        usedReferralCode: data.usedReferralCode,  // 从领域模型获取推荐人的推荐码
        ancestorPath: data.referralChain,
        depth: data.referralChain.length,
        rootUserId: data.referralChain.length > 0 ? data.referralChain[data.referralChain.length - 1] : null,
      },
    });

    return ReferralRelationship.reconstitute(this.mapToProps(saved));
  }

  async findByUserId(userId: bigint): Promise<ReferralRelationship | null> {
    const record = await this.prisma.referralRelationship.findUnique({
      where: { userId },
    });

    if (!record) return null;
    return ReferralRelationship.reconstitute(this.mapToProps(record));
  }

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

    if (!record) return null;
    return ReferralRelationship.reconstitute(this.mapToProps(record));
  }

  async findByReferralCode(code: string): Promise<ReferralRelationship | null> {
    const record = await this.prisma.referralRelationship.findUnique({
      where: { myReferralCode: code },
    });

    if (!record) return null;
    return ReferralRelationship.reconstitute(this.mapToProps(record));
  }

  async findDirectReferrals(userId: bigint): Promise<ReferralRelationship[]> {
    const records = await this.prisma.referralRelationship.findMany({
      where: { referrerId: userId },
      orderBy: { createdAt: 'desc' },
    });

    return records.map((r) => ReferralRelationship.reconstitute(this.mapToProps(r)));
  }

  async existsByReferralCode(code: string): Promise<boolean> {
    const count = await this.prisma.referralRelationship.count({
      where: { myReferralCode: code },
    });
    return count > 0;
  }

  async existsByUserId(userId: bigint): Promise<boolean> {
    const count = await this.prisma.referralRelationship.count({
      where: { userId },
    });
    return count > 0;
  }

  async getReferralChain(userId: bigint): Promise<bigint[]> {
    const record = await this.prisma.referralRelationship.findUnique({
      where: { userId },
      select: { ancestorPath: true },
    });

    if (!record) return [];
    return record.ancestorPath;
  }

  private mapToProps(record: {
    id: bigint;
    userId: bigint;
    accountSequence: string;  // 格式: D + YYMMDD + 5位序号
    referrerId: bigint | null;
    myReferralCode: string;
    usedReferralCode: string | null;  // 用户使用的推荐码（推荐人的推荐码）
    ancestorPath: bigint[];
    createdAt: Date;
    updatedAt: Date;
  }): ReferralRelationshipProps {
    return {
      id: record.id,
      userId: record.userId,
      accountSequence: record.accountSequence,
      referrerId: record.referrerId,
      referralCode: record.myReferralCode,
      usedReferralCode: record.usedReferralCode,
      referralChain: record.ancestorPath,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
    };
  }
}
