import { Injectable, Logger } from '@nestjs/common';
import { ReferralCodeRepository } from '../../infrastructure/repositories/referral-code.repository';
import { ReferralRelationshipRepository } from '../../infrastructure/repositories/referral-relationship.repository';
import { ReferralStatRepository } from '../../infrastructure/repositories/referral-stat.repository';

export interface RegisterWithCodeInput {
  /** The newly registered tenant's ID */
  tenantId: string;
  /** The admin user who registered */
  userId: string;
  /** Optional referral code the user entered during registration */
  referralCode?: string;
}

export interface RegisterWithCodeResult {
  /** The new tenant's own referral code (auto-generated) */
  myReferralCode: string;
}

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

  constructor(
    private readonly codeRepo: ReferralCodeRepository,
    private readonly relationshipRepo: ReferralRelationshipRepository,
    private readonly statRepo: ReferralStatRepository,
  ) {}

  async execute(input: RegisterWithCodeInput): Promise<RegisterWithCodeResult> {
    const { tenantId, userId, referralCode } = input;

    // 1. Auto-create the new tenant's own referral code
    const myCode = await this.codeRepo.create(tenantId, userId);

    // 2. Ensure stats row exists for the new tenant
    await this.statRepo.upsert(tenantId);

    // 3. If a referral code was provided, create the relationship
    if (referralCode) {
      const codeEntity = await this.codeRepo.findByCode(referralCode);
      if (!codeEntity) {
        this.logger.warn(`Referral code not found: ${referralCode} for tenant ${tenantId}`);
        return { myReferralCode: myCode.code };
      }

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

      // Prevent double-registration (idempotent)
      const existing = await this.relationshipRepo.findByReferredTenantId(tenantId);
      if (existing) {
        this.logger.warn(`Tenant ${tenantId} already has a referral relationship`);
        return { myReferralCode: myCode.code };
      }

      // Create level-1 (direct) relationship
      await this.relationshipRepo.create(
        codeEntity.tenantId,
        tenantId,
        referralCode,
        1,
      );

      // Update direct count for the referrer
      await this.statRepo.upsert(codeEntity.tenantId);
      await this.statRepo.incrementDirectCount(codeEntity.tenantId);

      // Also create level-2 relationship if the referrer was themselves referred
      const referrerRelationship = await this.relationshipRepo.findByReferredTenantId(
        codeEntity.tenantId,
      );
      if (referrerRelationship) {
        await this.relationshipRepo.create(
          referrerRelationship.referrerTenantId,
          tenantId,
          referralCode,
          2,
        );
      }

      this.logger.log(
        `Referral relationship created: ${codeEntity.tenantId} → ${tenantId} (code: ${referralCode})`,
      );
    }

    return { myReferralCode: myCode.code };
  }
}
