import { Injectable } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { UserReferralRelationship, UserReferralStatus } from '../../domain/entities/user-referral-relationship.entity';

@Injectable()
export class UserReferralRelationshipRepository {
  constructor(@InjectDataSource() private readonly ds: DataSource) {}

  async create(
    referrerUserId: string,
    referredUserId: string,
    referralCode: string,
    level: 1 | 2,
  ): Promise<UserReferralRelationship> {
    const rows = await this.ds.query(
      `INSERT INTO public.user_referral_relationships
         (referrer_user_id, referred_user_id, referral_code, level)
       VALUES ($1, $2, $3, $4)
       ON CONFLICT (referred_user_id) DO NOTHING
       RETURNING *`,
      [referrerUserId, referredUserId, referralCode, level],
    );
    return rows[0] ? this.map(rows[0]) : this.findByReferredUserId(referredUserId) as Promise<UserReferralRelationship>;
  }

  async findByReferredUserId(userId: string): Promise<UserReferralRelationship | null> {
    const rows = await this.ds.query(
      `SELECT * FROM public.user_referral_relationships WHERE referred_user_id = $1`,
      [userId],
    );
    return rows[0] ? this.map(rows[0]) : null;
  }

  /** Direct circle members (level-1 referrals made by this user). */
  async findByReferrerUserId(
    userId: string,
    limit = 20,
    offset = 0,
  ): Promise<{ items: UserReferralRelationship[]; total: number }> {
    const [rows, count] = await Promise.all([
      this.ds.query(
        `SELECT * FROM public.user_referral_relationships
         WHERE referrer_user_id = $1 AND level = 1
         ORDER BY created_at DESC LIMIT $2 OFFSET $3`,
        [userId, limit, offset],
      ),
      this.ds.query(
        `SELECT COUNT(*)::int AS total FROM public.user_referral_relationships
         WHERE referrer_user_id = $1 AND level = 1`,
        [userId],
      ),
    ]);
    return { items: rows.map((r: any) => this.map(r)), total: count[0]?.total ?? 0 };
  }

  async updateStatus(
    id: string,
    status: UserReferralStatus,
    timestamps: { activatedAt?: Date; rewardedAt?: Date } = {},
  ): Promise<void> {
    await this.ds.query(
      `UPDATE public.user_referral_relationships
       SET status = $2,
           activated_at = COALESCE($3, activated_at),
           rewarded_at  = COALESCE($4, rewarded_at)
       WHERE id = $1`,
      [id, status, timestamps.activatedAt ?? null, timestamps.rewardedAt ?? null],
    );
  }

  /** Admin: list all user-level circle relationships (paginated). */
  async findAll(
    status?: UserReferralStatus,
    limit = 50,
    offset = 0,
  ): Promise<{ items: UserReferralRelationship[]; total: number }> {
    const where = status ? `WHERE status = $3` : '';
    const params = status ? [limit, offset, status] : [limit, offset];
    const [rows, count] = await Promise.all([
      this.ds.query(
        `SELECT * FROM public.user_referral_relationships ${where} ORDER BY created_at DESC LIMIT $1 OFFSET $2`,
        params,
      ),
      this.ds.query(
        `SELECT COUNT(*)::int AS total FROM public.user_referral_relationships ${where}`,
        status ? [status] : [],
      ),
    ]);
    return { items: rows.map((r: any) => this.map(r)), total: count[0]?.total ?? 0 };
  }

  /** Count recurring-type point transactions already issued for a relationship. */
  async countRecurringRewards(relationshipId: string): Promise<number> {
    const rows = await this.ds.query(
      `SELECT COUNT(*)::int AS cnt FROM public.user_point_transactions
       WHERE ref_id = $1 AND type IN ('REFERRAL_RECURRING', 'REFERRAL_L2')`,
      [relationshipId],
    );
    return rows[0]?.cnt ?? 0;
  }

  private map(r: any): UserReferralRelationship {
    return {
      id: r.id,
      referrerUserId: r.referrer_user_id,
      referredUserId: r.referred_user_id,
      referralCode: r.referral_code,
      level: r.level,
      status: r.status,
      activatedAt: r.activated_at,
      rewardedAt: r.rewarded_at,
      createdAt: r.created_at,
    };
  }
}
