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

export interface DailyBonus {
  id: number;
  userId: number;
  bonusAmount: number;
  multiplier: number;
  loginStreak: number;
  claimedAt: Date;
  createdAt: Date;
}

const BONUS_CONFIG = {
  baseBonus: 100, // Base bonus in SC
  maxMultiplier: 5, // Max multiplier for 5+ day streak
  streakResetDays: 1, // Reset streak if not claimed within this many days
};

export async function checkDailyBonus(userId: number): Promise<{
  canClaim: boolean;
  bonusAmount: number;
  multiplier: number;
  loginStreak: number;
  lastClaimDate: Date | null;
}> {
  const db = await getDb();
  if (!db) {
    return {
      canClaim: false,
      bonusAmount: 0,
      multiplier: 1,
      loginStreak: 0,
      lastClaimDate: null,
    };
  }

  // Get last claimed bonus
  const lastBonus = await db
    .select()
    .from(dailyBonuses)
    .where(eq(dailyBonuses.userId, userId))
    .orderBy(dailyBonuses.claimedAt)
    .limit(1);

  const lastClaimDate = lastBonus[0]?.claimedAt || null;
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());

  // Check if already claimed today
  if (lastClaimDate) {
    const lastClaimDay = new Date(
      lastClaimDate.getFullYear(),
      lastClaimDate.getMonth(),
      lastClaimDate.getDate()
    );
    if (lastClaimDay.getTime() === today.getTime()) {
      return {
        canClaim: false,
        bonusAmount: 0,
        multiplier: 1,
        loginStreak: lastBonus[0].loginStreak || 1,
        lastClaimDate,
      };
    }
  }

  // Calculate login streak
  let loginStreak = 1;
  if (lastClaimDate) {
    const lastClaimDay = new Date(
      lastClaimDate.getFullYear(),
      lastClaimDate.getMonth(),
      lastClaimDate.getDate()
    );
    const daysDifference = Math.floor(
      (today.getTime() - lastClaimDay.getTime()) / (1000 * 60 * 60 * 24)
    );

    if (daysDifference === 1) {
      // Consecutive day
      loginStreak = (lastBonus[0].loginStreak || 1) + 1;
    } else if (daysDifference > BONUS_CONFIG.streakResetDays) {
      // Streak broken
      loginStreak = 1;
    } else {
      // Same day or within reset window
      loginStreak = lastBonus[0].loginStreak || 1;
    }
  }

  // Calculate multiplier (increases with streak, max 5x)
  const multiplier = Math.min(
    1 + (loginStreak - 1) * 0.5,
    BONUS_CONFIG.maxMultiplier
  );
  const bonusAmount = BONUS_CONFIG.baseBonus * multiplier;

  return {
    canClaim: true,
    bonusAmount: Math.floor(bonusAmount),
    multiplier: Math.round(multiplier * 100) / 100,
    loginStreak,
    lastClaimDate,
  };
}

export async function claimDailyBonus(userId: number): Promise<{
  success: boolean;
  bonusAmount: number;
  newBalance: number;
  loginStreak: number;
}> {
  const db = await getDb();
  if (!db) {
    return {
      success: false,
      bonusAmount: 0,
      newBalance: 0,
      loginStreak: 0,
    };
  }

  const bonusInfo = await checkDailyBonus(userId);

  if (!bonusInfo.canClaim) {
    return {
      success: false,
      bonusAmount: 0,
      newBalance: 0,
      loginStreak: bonusInfo.loginStreak,
    };
  }

  // Record the bonus claim
  await db.insert(dailyBonuses).values({
    userId,
    bonusAmount: bonusInfo.bonusAmount,
    multiplier: bonusInfo.multiplier,
    loginStreak: bonusInfo.loginStreak,
    claimedAt: new Date(),
    createdAt: new Date(),
  });

  // Update wallet with bonus (add to SC balance)
  const userWallet = await db
    .select()
    .from(wallets)
    .where(eq(wallets.userId, userId))
    .limit(1);

  if (userWallet.length === 0) {
    return {
      success: false,
      bonusAmount: 0,
      newBalance: 0,
      loginStreak: bonusInfo.loginStreak,
    };
  }

  const currentBalance = parseFloat(userWallet[0].scBalance || "0");
  const newBalance = currentBalance + bonusInfo.bonusAmount;

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

  return {
    success: true,
    bonusAmount: bonusInfo.bonusAmount,
    newBalance,
    loginStreak: bonusInfo.loginStreak,
  };
}

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

  const lastBonus = await db
    .select()
    .from(dailyBonuses)
    .where(eq(dailyBonuses.userId, userId))
    .orderBy(dailyBonuses.claimedAt)
    .limit(1);

  if (lastBonus.length === 0) return 0;

  const lastClaimDate = lastBonus[0].claimedAt;
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const lastClaimDay = new Date(
    lastClaimDate.getFullYear(),
    lastClaimDate.getMonth(),
    lastClaimDate.getDate()
  );

  const daysDifference = Math.floor(
    (today.getTime() - lastClaimDay.getTime()) / (1000 * 60 * 60 * 24)
  );

  if (daysDifference === 0) {
    // Claimed today
    return lastBonus[0].loginStreak || 1;
  } else if (daysDifference === 1) {
    // Can claim tomorrow
    return lastBonus[0].loginStreak || 1;
  } else {
    // Streak broken
    return 0;
  }
}
