import {
  Injectable,
  Logger,
  Inject,
  NotFoundException,
  ConflictException,
  BadRequestException,
} from '@nestjs/common';
import { ReferralProfile } from '../../domain/entities/referral-profile.entity';
import { ReferralCode } from '../../domain/value-objects/referral-code.vo';
import { ReferralChain } from '../../domain/value-objects/referral-chain.vo';
import {
  REFERRAL_PROFILE_REPOSITORY,
  IReferralProfileRepository,
} from '../../domain/repositories/referral-profile.repository.interface';

export interface CreateReferralCommand {
  userId: string;
  usedCode: string | null; // 注册时填写的推荐码 (推荐人的码)
}

export interface ReferralInfo {
  userId: string;
  referralCode: string;
  referrerId: string | null;
  usedCode: string | null;
  referralChain: string[];
  directReferralCount: number;
  createdAt: Date;
}

export interface DirectReferralItem {
  userId: string;
  referralCode: string;
  joinedAt: Date;
}

@Injectable()
export class ReferralService {
  private readonly logger = new Logger(ReferralService.name);

  constructor(
    @Inject(REFERRAL_PROFILE_REPOSITORY)
    private readonly profileRepo: IReferralProfileRepository,
  ) {}

  /**
   * 用户注册后创建推荐档案
   * 由 UserRegisteredHandler 在收到 Kafka 事件后调用
   */
  async createProfile(command: CreateReferralCommand): Promise<{ referralCode: string }> {
    if (await this.profileRepo.existsByUserId(command.userId)) {
      this.logger.warn(`推荐档案已存在, userId=${command.userId}`);
      const existing = await this.profileRepo.findByUserId(command.userId);
      return { referralCode: existing!.referralCode };
    }

    // 生成唯一推荐码
    const referralCode = await this.generateUniqueCode();

    // 查找推荐人
    let referrerId: string | null = null;
    let referralChain: string[] = [];

    if (command.usedCode) {
      const referrerProfile = await this.profileRepo.findByCode(command.usedCode);
      if (!referrerProfile) {
        // 推荐码无效，静默忽略 (不阻止注册)
        this.logger.warn(`无效推荐码 ${command.usedCode}, userId=${command.userId}, 忽略推荐关系`);
      } else {
        // 防止自引用
        if (referrerProfile.userId === command.userId) {
          throw new BadRequestException('不能使用自己的推荐码');
        }

        // 防止循环推荐
        const chain = ReferralChain.fromArray(referrerProfile.referralChain);
        if (chain.contains(command.userId)) {
          this.logger.warn(`检测到循环推荐, userId=${command.userId}`);
        } else {
          referrerId = referrerProfile.userId;
          referralChain = ReferralChain.buildFromReferrer(
            referrerProfile.userId,
            referrerProfile.referralChain,
          ).toArray();

          // 递增推荐人的直推计数
          referrerProfile.incrementDirectReferral();
          await this.profileRepo.save(referrerProfile);
        }
      }
    }

    const profile = ReferralProfile.create({
      userId: command.userId,
      referralCode,
      referrerId,
      usedCode: command.usedCode ? command.usedCode.toUpperCase() : null,
      referralChain,
    });

    const saved = await this.profileRepo.save(profile);
    this.logger.log(
      `推荐档案已创建: userId=${command.userId} code=${referralCode} referrer=${referrerId ?? 'none'}`,
    );

    return { referralCode: saved.referralCode };
  }

  /** 获取我的推荐信息 */
  async getMyInfo(userId: string): Promise<ReferralInfo> {
    const profile = await this.profileRepo.findByUserId(userId);
    if (!profile) {
      throw new NotFoundException('推荐档案不存在');
    }
    return this.toInfo(profile);
  }

  /** 验证推荐码是否有效 */
  async validateCode(code: string): Promise<{ valid: boolean; referrerId?: string }> {
    const profile = await this.profileRepo.findByCode(code);
    if (!profile) return { valid: false };
    return { valid: true, referrerId: profile.userId };
  }

  /** 获取直推列表 */
  async getDirectReferrals(
    userId: string,
    offset = 0,
    limit = 20,
  ): Promise<{ items: DirectReferralItem[]; total: number }> {
    const [profiles, total] = await this.profileRepo.findDirectReferrals(userId, offset, limit);
    return {
      items: profiles.map((p) => ({
        userId: p.userId,
        referralCode: p.referralCode,
        joinedAt: p.createdAt,
      })),
      total,
    };
  }

  /* ── Private ── */

  private async generateUniqueCode(maxRetries = 10): Promise<string> {
    for (let i = 0; i < maxRetries; i++) {
      const code = ReferralCode.generate().value;
      if (!(await this.profileRepo.existsByCode(code))) {
        return code;
      }
    }
    throw new Error('推荐码生成失败，请重试');
  }

  private toInfo(profile: ReferralProfile): ReferralInfo {
    return {
      userId: profile.userId,
      referralCode: profile.referralCode,
      referrerId: profile.referrerId,
      usedCode: profile.usedCode,
      referralChain: profile.referralChain,
      directReferralCount: profile.directReferralCount,
      createdAt: profile.createdAt,
    };
  }
}
