import { getDb } from "../db.ts";
import { referrals, wallets } from "../../drizzle/schema.ts";
import { eq, and } from "drizzle-orm";
import crypto from "crypto";

export interface Referral {
  id: number;
  referrerId: number;
  referredUserId: number;
  referralCode: string;
  rewardAmount: number;
  status: "pending" | "completed";
  createdAt: Date;
  completedAt: Date | null;
}

const REFERRAL_CONFIG = {
  referrerReward: 1, // SC bonus for successful referral
  refereeReward: 0, // SC bonus for new user using referral code (no bonus for referee)
  minActivationBet: 100, // Minimum bet to activate referral
};

export function generateReferralCode(userId: number): string {
  const timestamp = Date.now().toString(36);
  const randomStr = crypto.randomBytes(4).toString("hex");
  return `REF${userId}${timestamp}${randomStr}`.toUpperCase().slice(0, 12);
}

export async function createReferralCode(userId: number): Promise<string> {
  const db = await getDb();
  if (!db) return "";

  const code = generateReferralCode(userId);

  // Check if code already exists for this user
  const existing = await db
    .select()
    .from(referrals)
    .where(and(eq(referrals.referrerId, userId), eq(referrals.referralCode, code)))
    .limit(1);

  if (existing.length > 0) {
    return code;
  }

  // Store the referral code (we'll create it when someone uses it)
  return code;
}

export async function getReferralCode(userId: number): Promise<string | null> {
  const db = await getDb();
  if (!db) return null;

  // For now, generate a code for the user
  // In production, you'd fetch from a referral_codes table
  return generateReferralCode(userId);
}

export async function applyReferralCode(
  newUserId: number,
  referralCode: string
): Promise<{ success: boolean; message: string }> {
  const db = await getDb();
  if (!db) {
    return { success: false, message: "Database connection failed" };
  }

  // Extract referrer ID from code (format: REF{userId}...)
  const referrerIdMatch = referralCode.match(/REF(\d+)/);
  if (!referrerIdMatch) {
    return { success: false, message: "Invalid referral code format" };
  }

  const referrerId = parseInt(referrerIdMatch[1]);

  if (referrerId === newUserId) {
    return { success: false, message: "Cannot use your own referral code" };
  }

  // Create referral record
  try {
    await db.insert(referrals).values({
      referrerId,
      referredUserId: newUserId,
      referralCode,
      rewardAmount: REFERRAL_CONFIG.refereeReward,
      status: "pending",
      createdAt: new Date(),
      completedAt: null,
    });

    // Award referee bonus immediately
    const newUserWallet = await db
      .select()
      .from(wallets)
      .where(eq(wallets.userId, newUserId))
      .limit(1);

    if (newUserWallet.length > 0) {
      const currentBalance = parseFloat(newUserWallet[0].scBalance || "0");
      const newBalance = currentBalance + REFERRAL_CONFIG.refereeReward;

      await db
        .update(wallets)
        .set({ scBalance: newBalance.toString() })
        .where(eq(wallets.userId, newUserId));
    }

    return {
      success: true,
      message: `Referral applied! You earned ${REFERRAL_CONFIG.refereeReward} SC`,
    };
  } catch (error) {
    return { success: false, message: "Failed to apply referral code" };
  }
}

export async function completeReferral(referralId: number): Promise<void> {
  const db = await getDb();
  if (!db) return;

  const referral = await db
    .select()
    .from(referrals)
    .where(eq(referrals.id, referralId))
    .limit(1);

  if (referral.length === 0 || referral[0].status === "completed") {
    return;
  }

  // Update referral status
  await db
    .update(referrals)
    .set({ status: "completed", completedAt: new Date() })
    .where(eq(referrals.id, referralId));

  // Award referrer bonus
  const referrerWallet = await db
    .select()
    .from(wallets)
    .where(eq(wallets.userId, referral[0].referrerId))
    .limit(1);

  if (referrerWallet.length > 0) {
    const currentBalance = parseFloat(referrerWallet[0].scBalance || "0");
    const newBalance = currentBalance + REFERRAL_CONFIG.referrerReward;

    await db
      .update(wallets)
      .set({ scBalance: newBalance.toString() })
      .where(eq(wallets.userId, referral[0].referrerId));
  }
}

export async function getReferralStats(userId: number): Promise<{
  totalReferrals: number;
  completedReferrals: number;
  pendingReferrals: number;
  totalEarnings: number;
  referralCode: string;
}> {
  const db = await getDb();
  if (!db) {
    return {
      totalReferrals: 0,
      completedReferrals: 0,
      pendingReferrals: 0,
      totalEarnings: 0,
      referralCode: "",
    };
  }

  const userReferrals = await db
    .select()
    .from(referrals)
    .where(eq(referrals.referrerId, userId));

  const completedCount = userReferrals.filter(
    (r) => r.status === "completed"
  ).length;
  const pendingCount = userReferrals.filter(
    (r) => r.status === "pending"
  ).length;
  const totalEarnings = completedCount * REFERRAL_CONFIG.referrerReward;
  const referralCode = generateReferralCode(userId);

  return {
    totalReferrals: userReferrals.length,
    completedReferrals: completedCount,
    pendingReferrals: pendingCount,
    totalEarnings,
    referralCode,
  };
}

export async function getTopReferrers(limit: number = 10): Promise<
  Array<{
    userId: number;
    totalReferrals: number;
    completedReferrals: number;
    totalEarnings: number;
  }>
> {
  const db = await getDb();
  if (!db) return [];

  const allReferrals = await db.select().from(referrals);

  // Group by referrer and calculate stats
  const referrerStats: Record<
    number,
    {
      userId: number;
      totalReferrals: number;
      completedReferrals: number;
      totalEarnings: number;
    }
  > = {};

  for (const ref of allReferrals) {
    if (!referrerStats[ref.referrerId]) {
      referrerStats[ref.referrerId] = {
        userId: ref.referrerId,
        totalReferrals: 0,
        completedReferrals: 0,
        totalEarnings: 0,
      };
    }

    referrerStats[ref.referrerId].totalReferrals++;
    if (ref.status === "completed") {
      referrerStats[ref.referrerId].completedReferrals++;
      referrerStats[ref.referrerId].totalEarnings +=
        REFERRAL_CONFIG.referrerReward;
    }
  }

  // Sort by total earnings and return top N
  return Object.values(referrerStats)
    .sort((a, b) => b.totalEarnings - a.totalEarnings)
    .slice(0, limit);
}
