import { Injectable, Logger } from '@nestjs/common';
import { UserReferralCodeRepository } from '../../infrastructure/repositories/user-referral-code.repository';
import { UserReferralRelationshipRepository } from '../../infrastructure/repositories/user-referral-relationship.repository';
import { UserPointRepository } from '../../infrastructure/repositories/user-point.repository';

export interface RegisterUserReferralInput {
  userId: string;
  /** Optional: personal referral code entered by the user at registration */
  userReferralCode?: string;
}

export interface RegisterUserReferralResult {
  myCode: string;
}

// Welcome bonus points awarded to a newly invited user
const WELCOME_BONUS_POINTS = 200;

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

  constructor(
    private readonly codeRepo: UserReferralCodeRepository,
    private readonly relRepo: UserReferralRelationshipRepository,
    private readonly pointRepo: UserPointRepository,
  ) {}

  async execute(input: RegisterUserReferralInput): Promise<RegisterUserReferralResult> {
    const { userId, userReferralCode } = input;

    // 1. Auto-create this user's own referral code
    const myCode = await this.codeRepo.createForUser(userId);

    // 2. If a referral code was provided, establish the relationship
    if (userReferralCode) {
      const codeEntity = await this.codeRepo.findByCode(userReferralCode);
      if (!codeEntity) {
        this.logger.warn(`User referral code not found: ${userReferralCode} for user ${userId}`);
        return { myCode: myCode.code };
      }

      // Prevent self-referral
      if (codeEntity.userId === userId) {
        this.logger.warn(`Self-referral attempt by user ${userId}`);
        return { myCode: myCode.code };
      }

      // Prevent double-referral (idempotent)
      const existing = await this.relRepo.findByReferredUserId(userId);
      if (existing) {
        this.logger.warn(`User ${userId} already has a referral relationship`);
        return { myCode: myCode.code };
      }

      // Create level-1 (direct) relationship
      const rel = await this.relRepo.create(codeEntity.userId, userId, userReferralCode, 1);

      // Award welcome bonus to the newly referred user
      await this.pointRepo.addTransaction(
        userId,
        WELCOME_BONUS_POINTS,
        'REFERRAL_WELCOME',
        rel.id,
        `Welcome bonus — invited by user ${codeEntity.userId}`,
      );

      // Check if the referrer was themselves referred (level-2 chain)
      const referrerRel = await this.relRepo.findByReferredUserId(codeEntity.userId);
      if (referrerRel) {
        await this.relRepo.create(
          referrerRel.referrerUserId,
          userId,
          userReferralCode,
          2,
        );
      }

      this.logger.log(
        `User referral created: ${codeEntity.userId} → ${userId} (code: ${userReferralCode})`,
      );
    }

    return { myCode: myCode.code };
  }
}
