const db = require('../db');

async function upsertLeaderboardEntry(userId, grade, { elo, bestTime, correctAnswers = 0 } = {}) {
  const existing = await db.leaderboardEntry.findUnique({
    where: { userId_grade: { userId, grade } },
  });

  return db.leaderboardEntry.upsert({
    where: { userId_grade: { userId, grade } },
    create: {
      userId,
      grade,
      elo: elo ?? 800,
      bestTime: bestTime ?? null,
      gamesPlayed: 1,
      totalCorrect: correctAnswers,
    },
    update: {
      ...(elo !== undefined && { elo }),
      ...(bestTime !== undefined && (existing?.bestTime == null || bestTime < existing.bestTime)
        ? { bestTime }
        : {}),
      gamesPlayed:  { increment: 1 },
      totalCorrect: { increment: correctAnswers },
    },
  });
}

async function getLeaderboard(grade, sortBy = 'elo', limit = 10) {
  const orderBy = sortBy === 'bestTime'
    ? { bestTime: { sort: 'asc', nulls: 'last' } }
    : { elo: 'desc' };

  const entries = await db.leaderboardEntry.findMany({
    where: { grade },
    orderBy,
    take: limit,
    include: {
      user: { select: { displayName: true, avatarUrl: true, username: true } },
    },
  });

  return entries.map((entry, index) => ({ ...entry, ...entry.user, rank: index + 1 }));
}

async function getUserRank(userId, grade, sortBy = 'elo') {
  const entry = await db.leaderboardEntry.findUnique({
    where: { userId_grade: { userId, grade } },
  });

  if (!entry) return null;

  if (sortBy === 'bestTime') {
    if (entry.bestTime === null) return { rank: null, entry };
    const count = await db.leaderboardEntry.count({
      where: {
        grade,
        AND: [
          { bestTime: { not: null } },
          { bestTime: { lt: entry.bestTime } },
        ],
      },
    });
    return { rank: count + 1, entry };
  }

  const count = await db.leaderboardEntry.count({
    where: { grade, elo: { gt: entry.elo } },
  });
  return { rank: count + 1, entry };
}

module.exports = { upsertLeaderboardEntry, getLeaderboard, getUserRank };
