const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags } = require("discord.js"); const { mClient } = require("../index"); const { getCookieBalance, getUnixTime } = require("./cookieEconomy"); const DATABASE_NAME = process.env.M_DB; const COLLECTIONS = { stats: "stats_profiles", achievements: "items_achievements", badges: "guild_badges", achievementConfig: "config_achievements" }; let profileSystemInitPromise = null; const DEFAULT_ACHIEVEMENTS = [ { achievementId: "stolen_1000", name: "Light Fingers", description: "Steal 1,000 Cookies from other players.", requirement: "Steal 1,000 Cookies total.", category: "stealing", stat: "economy.stolenTotal", target: 1000, emoji: "๐Ÿงค" }, { achievementId: "stolen_10000", name: "Career Criminal", description: "Steal 10,000 Cookies from other players.", requirement: "Steal 10,000 Cookies total.", category: "stealing", stat: "economy.stolenTotal", target: 10000, emoji: "๐Ÿ•ต๏ธ" }, { achievementId: "stolen_100000", name: "Grand Theft Cookie", description: "Steal 100,000 Cookies from other players.", requirement: "Steal 100,000 Cookies total.", category: "stealing", stat: "economy.stolenTotal", target: 100000, emoji: "๐Ÿ’ฐ" }, { achievementId: "stolen_unique_3", name: "Making the Rounds", description: "Successfully steal from 3 different players.", requirement: "Steal from 3 unique players.", category: "stealing", stat: "unique.playersStolenFrom", measure: "arrayLength", target: 3, emoji: "๐ŸŽฏ" }, { achievementId: "stolen_unique_10", name: "Equal Opportunity Thief", description: "Successfully steal from 10 different players.", requirement: "Steal from 10 unique players.", category: "stealing", stat: "unique.playersStolenFrom", measure: "arrayLength", target: 10, emoji: "๐Ÿ—บ๏ธ" }, { achievementId: "stolen_from_me_1000", name: "Easy Pickings", description: "Have 1,000 Cookies stolen from you.", requirement: "Lose 1,000 Cookies to other players stealing.", category: "victim", stat: "economy.stolenFromMeTotal", target: 1000, emoji: "๐Ÿ’ธ" }, { achievementId: "stolen_from_me_10000", name: "Lock the Door", description: "Have 10,000 Cookies stolen from you.", requirement: "Lose 10,000 Cookies to other players stealing.", category: "victim", stat: "economy.stolenFromMeTotal", target: 10000, emoji: "๐Ÿšช" }, { achievementId: "stolen_by_unique_3", name: "Marked", description: "Be successfully stolen from by 3 different players.", requirement: "Be stolen from by 3 unique players.", category: "victim", stat: "unique.playersStolenBy", measure: "arrayLength", target: 3, emoji: "๐Ÿ‘€" }, { achievementId: "stolen_by_unique_10", name: "Criminal Magnet", description: "Be successfully stolen from by 10 different players.", requirement: "Be stolen from by 10 unique players.", category: "victim", stat: "unique.playersStolenBy", measure: "arrayLength", target: 10, emoji: "๐Ÿงฒ" }, { achievementId: "obtained_10000", name: "Growing Stash", description: "Obtain 10,000 Cookies over your lifetime.", requirement: "Obtain 10,000 Cookies from all sources.", category: "economy", stat: "economy.cookiesObtainedTotal", target: 10000, emoji: "๐Ÿช" }, { achievementId: "obtained_100000", name: "Cookie Magnate", description: "Obtain 100,000 Cookies over your lifetime.", requirement: "Obtain 100,000 Cookies from all sources.", category: "economy", stat: "economy.cookiesObtainedTotal", target: 100000, emoji: "๐Ÿ’ฐ" }, { achievementId: "obtained_1000000", name: "Crumb Tycoon", description: "Obtain 1,000,000 Cookies over your lifetime.", requirement: "Obtain 1,000,000 Cookies from all sources.", category: "economy", stat: "economy.cookiesObtainedTotal", target: 1000000, emoji: "๐Ÿ‘‘" }, { achievementId: "vault_stolen_1000", name: "Testing the Locks", description: "Steal 1,000 Cookies from the Bot Vault.", requirement: "Steal 1,000 Cookies from the Bot Vault.", category: "vault", stat: "economy.vaultStolenTotal", target: 1000, emoji: "๐Ÿฆ" }, { achievementId: "vault_stolen_10000", name: "Vault Regular", description: "Steal 10,000 Cookies from the Bot Vault.", requirement: "Steal 10,000 Cookies from the Bot Vault.", category: "vault", stat: "economy.vaultStolenTotal", target: 10000, emoji: "๐Ÿฅท" }, { achievementId: "lost_10000", name: "Expensive Hobby", description: "Lose 10,000 Cookies.", requirement: "Lose 10,000 Cookies total.", category: "economy", stat: "economy.cookiesLostTotal", target: 10000, emoji: "๐Ÿ”ฅ" }, { achievementId: "lost_100000", name: "Financial Catastrophe", description: "Lose 100,000 Cookies.", requirement: "Lose 100,000 Cookies total.", category: "economy", stat: "economy.cookiesLostTotal", target: 100000, emoji: "๐Ÿ’€" }, { achievementId: "win_streak_3", name: "On a Roll", description: "Win 3 games in a row.", requirement: "Reach a 3-game winning streak.", category: "games", stat: "streaks.bestWin", target: 3, emoji: "๐Ÿ€" }, { achievementId: "win_streak_10", name: "Can't Stop Won't Stop", description: "Win 10 games in a row.", requirement: "Reach a 10-game winning streak.", category: "games", stat: "streaks.bestWin", target: 10, emoji: "๐Ÿ”ฅ" }, { achievementId: "loss_streak_3", name: "Rough Night", description: "Lose 3 games in a row.", requirement: "Reach a 3-game losing streak.", category: "games", stat: "streaks.bestLoss", target: 3, emoji: "๐Ÿ˜ฌ" }, { achievementId: "loss_streak_10", name: "Digging Deeper", description: "Lose 10 games in a row.", requirement: "Reach a 10-game losing streak.", category: "games", stat: "streaks.bestLoss", target: 10, emoji: "๐Ÿ•ณ๏ธ" }, { achievementId: "given_10000", name: "Sharing Is Caring", description: "Give 10,000 Cookies to other players.", requirement: "Give 10,000 Cookies to other players total.", category: "economy", stat: "economy.cookiesGivenTotal", target: 10000, emoji: "๐ŸŽ" }, { achievementId: "given_50000", name: "Community Baker", description: "Give 50,000 Cookies to other players.", requirement: "Give 50,000 Cookies to other players total.", category: "economy", stat: "economy.cookiesGivenTotal", target: 50000, emoji: "๐Ÿค" }, { achievementId: "games_won_10", name: "House Regular", description: "Win 10 Crumb Saucer games.", requirement: "Win 10 games total.", category: "games", stat: "games.total.won", target: 10, emoji: "๐ŸŽฒ" }, { achievementId: "games_won_50", name: "House Favorite", description: "Win 50 Crumb Saucer games.", requirement: "Win 50 games total.", category: "games", stat: "games.total.won", target: 50, emoji: "๐Ÿ†" }, { achievementId: "slots_won_10", name: "Reel Deal", description: "Win 10 Slots spins.", requirement: "Win 10 Slots games.", category: "games", stat: "games.slots.won", target: 10, emoji: "๐ŸŽฐ" }, { achievementId: "blackjack_won_10", name: "Card Counter-ish", description: "Win 10 Blackjack hands.", requirement: "Win 10 Blackjack games.", category: "games", stat: "games.blackjack.won", target: 10, emoji: "๐Ÿƒ" }, { achievementId: "roulette_won_10", name: "Wheel Watcher", description: "Win 10 Roulette bets.", requirement: "Win 10 Roulette games.", category: "games", stat: "games.roulette.won", target: 10, emoji: "๐ŸŽก" }, { achievementId: "heist_won_10", name: "Professional", description: "Complete 10 successful Vault Heists.", requirement: "Win 10 Vault Heists.", category: "games", stat: "games.heist.won", target: 10, emoji: "๐Ÿฆ" } ]; const DEFAULT_BADGES = [ { badgeId: "first_100k_cookies", name: "Cookie Pioneer", description: "First player to hold 100,000 Cookies.", emoji: "๐Ÿช", ownerId: null, unlockedAt: null }, { badgeId: "first_1m_cookies", name: "Cookie Millionaire", description: "First player to hold 1,000,000 Cookies.", emoji: "๐Ÿ‘‘", ownerId: null, unlockedAt: null }, { badgeId: "first_100k_vault_stolen", name: "Vault Breaker", description: "First player to steal 100,000 Cookies from the Bot Vault.", emoji: "๐Ÿฆ", ownerId: null, unlockedAt: null } ]; function getProfileCollections() { if (!DATABASE_NAME) throw new Error("M_DB is not configured in .env"); const db = mClient.db(DATABASE_NAME); return { db, stats: db.collection(COLLECTIONS.stats), achievements: db.collection(COLLECTIONS.achievements), badges: db.collection(COLLECTIONS.badges), achievementConfig: db.collection(COLLECTIONS.achievementConfig) }; } async function ensureProfileSystem() { if (profileSystemInitPromise) return profileSystemInitPromise; profileSystemInitPromise = (async () => { const { stats, achievements, badges, achievementConfig } = getProfileCollections(); await stats.createIndex({ userId: 1, guildId: 1 }, { unique: true }); await achievements.createIndex({ userId: 1, guildId: 1 }, { unique: true }); await badges.createIndex({ guildId: 1, badgeId: 1 }, { unique: true }); await achievementConfig.createIndex({ achievementId: 1 }, { unique: true }); for (const achievement of DEFAULT_ACHIEVEMENTS) { await achievementConfig.updateOne( { achievementId: achievement.achievementId }, { $setOnInsert: achievement }, { upsert: true } ); } })(); try { return await profileSystemInitPromise; } catch (error) { profileSystemInitPromise = null; throw error; } } async function ensureGuildBadges(guildId) { await ensureProfileSystem(); const { badges } = getProfileCollections(); for (const badge of DEFAULT_BADGES) { await badges.updateOne( { guildId, badgeId: badge.badgeId }, { $setOnInsert: { guildId, ...badge } }, { upsert: true } ); } } function getDefaultStats(userId, guildId) { return { userId, guildId, economy: { cookiesObtainedTotal: 0, cookiesLostTotal: 0, cookiesGivenTotal: 0, stolenTotal: 0, stolenFromMeTotal: 0, vaultStolenTotal: 0 }, unique: { playersStolenFrom: [], playersStolenBy: [] }, games: { total: { played: 0, won: 0, lost: 0, pushed: 0 }, slots: { played: 0, won: 0, lost: 0, pushed: 0 }, blackjack: { played: 0, won: 0, lost: 0, pushed: 0 }, roulette: { played: 0, won: 0, lost: 0, pushed: 0 }, heist: { played: 0, won: 0, lost: 0, pushed: 0 } }, streaks: { currentWin: 0, bestWin: 0, currentLoss: 0, bestLoss: 0 } }; } async function ensureStatsDocument(userId, guildId) { const { stats } = getProfileCollections(); await stats.updateOne( { userId, guildId }, { $setOnInsert: getDefaultStats(userId, guildId) }, { upsert: true } ); } async function ensureAchievementDocument(userId, guildId) { const { achievements } = getProfileCollections(); await achievements.updateOne( { userId, guildId }, { $setOnInsert: { userId, guildId, unlocked: {} } }, { upsert: true } ); } async function getProfileStats(userId, guildId) { const { stats } = getProfileCollections(); return await stats.findOne({ userId, guildId }) ?? getDefaultStats(userId, guildId); } async function trackProfileEvent(interaction, userId, event) { await ensureProfileSystem(); const guildId = interaction.guildId; if (!guildId || !userId || !event?.type) return; const { stats } = getProfileCollections(); await ensureStatsDocument(userId, guildId); switch (event.type) { case "cookie_gain": await stats.updateOne({ userId, guildId }, { $inc: { "economy.cookiesObtainedTotal": event.amount } }); break; case "cookie_loss": await stats.updateOne({ userId, guildId }, { $inc: { "economy.cookiesLostTotal": event.amount } }); break; case "cookies_given": await stats.updateOne({ userId, guildId }, { $inc: { "economy.cookiesGivenTotal": event.amount } }); break; case "steal_success": await stats.updateOne( { userId, guildId }, { $inc: { "economy.stolenTotal": event.amount }, $addToSet: { "unique.playersStolenFrom": event.targetUserId } } ); break; case "stolen_from_me": await stats.updateOne( { userId, guildId }, { $inc: { "economy.stolenFromMeTotal": event.amount }, $addToSet: { "unique.playersStolenBy": event.thiefUserId } } ); break; case "vault_steal": await stats.updateOne({ userId, guildId }, { $inc: { "economy.vaultStolenTotal": event.amount } }); break; case "game_result": await trackGameResult(userId, guildId, event); break; default: return; } const updatedStats = await getProfileStats(userId, guildId); await evaluateAchievements(interaction, userId, updatedStats, event.type); await evaluateBadges(interaction, userId, updatedStats); return updatedStats; } async function trackGameResult(userId, guildId, event) { const { stats } = getProfileCollections(); const game = String(event.game ?? "").toLowerCase(); if (!["slots", "blackjack", "roulette", "heist"].includes(game)) return; const result = String(event.result ?? "").toLowerCase(); const increment = { "games.total.played": 1, [`games.${game}.played`]: 1 }; const set = {}; if (result === "win") { increment["games.total.won"] = 1; increment[`games.${game}.won`] = 1; increment["streaks.currentWin"] = 1; set["streaks.currentLoss"] = 0; } else if (result === "loss") { increment["games.total.lost"] = 1; increment[`games.${game}.lost`] = 1; increment["streaks.currentLoss"] = 1; set["streaks.currentWin"] = 0; } else if (result === "push") { increment["games.total.pushed"] = 1; increment[`games.${game}.pushed`] = 1; } else { return; } await stats.updateOne( { userId, guildId }, { $inc: increment, ...(Object.keys(set).length ? { $set: set } : {}) } ); const current = await stats.findOne({ userId, guildId }); await stats.updateOne( { userId, guildId }, { $max: { "streaks.bestWin": current?.streaks?.currentWin ?? 0, "streaks.bestLoss": current?.streaks?.currentLoss ?? 0 } } ); } async function evaluateAchievements(interaction, userId, statsDocument, eventType = null) { const { achievements, achievementConfig } = getProfileCollections(); const guildId = interaction.guildId; await ensureAchievementDocument(userId, guildId); const relevantStats = getRelevantAchievementStats(eventType); const definitions = await achievementConfig.find( relevantStats ? { stat: { $in: relevantStats } } : {} ).toArray(); const unlockedDoc = await achievements.findOne({ userId, guildId }); const unlocked = unlockedDoc?.unlocked ?? {}; for (const definition of definitions) { if (unlocked[definition.achievementId]) continue; const currentValue = readStatValue(statsDocument, definition); if (currentValue < definition.target) continue; const field = `unlocked.${definition.achievementId}`; const result = await achievements.updateOne( { userId, guildId, [field]: { $exists: false } }, { $set: { [field]: getUnixTime() } } ); if (result.modifiedCount === 1) { await sendAchievementNotification(interaction, userId, definition); } } } async function evaluateBadges(interaction, userId, statsDocument) { const guildId = interaction.guildId; await ensureGuildBadges(guildId); const balance = await getCookieBalance(userId); if (balance >= 100000) await tryClaimBadge(interaction, userId, "first_100k_cookies"); if (balance >= 1000000) await tryClaimBadge(interaction, userId, "first_1m_cookies"); if ((statsDocument?.economy?.vaultStolenTotal ?? 0) >= 100000) { await tryClaimBadge(interaction, userId, "first_100k_vault_stolen"); } } async function tryClaimBadge(interaction, userId, badgeId) { const { badges } = getProfileCollections(); const guildId = interaction.guildId; const badge = await badges.findOneAndUpdate( { guildId, badgeId, ownerId: null }, { $set: { ownerId: userId, unlockedAt: getUnixTime() } }, { returnDocument: "after" } ); if (!badge || badge.ownerId !== userId) return; try { await interaction.channel.send({ embeds: [ new EmbedBuilder() .setTitle("๐Ÿ… Unique Badge Claimed!") .setDescription([ `${badge.emoji} **${badge.name}**`, "", `<@${userId}> claimed a guild-unique badge!`, "", badge.description, "", "*This badge can no longer be earned by another player.*" ].join("\n")) ] }); } catch {} } async function sendAchievementNotification(interaction, userId, achievement) { try { await interaction.channel.send({ embeds: [ new EmbedBuilder() .setTitle("๐Ÿ† Achievement Unlocked!") .setDescription([ `<@${userId}>`, "", `${achievement.emoji} **${achievement.name}**`, "", achievement.description ].join("\n")) ] }); } catch {} } function getRelevantAchievementStats(eventType) { switch (eventType) { case "cookie_gain": return ["economy.cookiesObtainedTotal"]; case "cookie_loss": return ["economy.cookiesLostTotal"]; case "cookies_given": return ["economy.cookiesGivenTotal"]; case "steal_success": return ["economy.stolenTotal", "unique.playersStolenFrom"]; case "stolen_from_me": return ["economy.stolenFromMeTotal", "unique.playersStolenBy"]; case "vault_steal": return ["economy.vaultStolenTotal"]; case "game_result": return ["streaks.bestWin", "streaks.bestLoss", "games.total.won", "games.slots.won", "games.blackjack.won", "games.roulette.won", "games.heist.won"]; default: return null; } } function readStatValue(document, definition) { const value = definition.stat .split(".") .reduce((current, key) => current?.[key], document); if (definition.measure === "arrayLength") { return Array.isArray(value) ? value.length : 0; } return Number(value ?? 0); } async function buildProfileOverview(guildId, user) { await ensureProfileSystem(); const stats = await getProfileStats(user.id, guildId); const balance = await getCookieBalance(user.id); const { achievements, badges, achievementConfig } = getProfileCollections(); const [achievementDoc, achievementCount, ownedBadges] = await Promise.all([ achievements.findOne({ userId: user.id, guildId }), achievementConfig.countDocuments(), badges.find({ guildId, ownerId: user.id }).toArray() ]); const unlockedCount = Object.keys(achievementDoc?.unlocked ?? {}).length; return new EmbedBuilder() .setTitle(`๐Ÿ‘ค ${user.globalName ?? user.username}'s Profile`) .setThumbnail(user.displayAvatarURL({ size: 256 })) .addFields( { name: "๐Ÿช Cookies", value: balance.toLocaleString(), inline: true }, { name: "๐Ÿ† Achievements", value: `${unlockedCount} / ${achievementCount}`, inline: true }, { name: "๐Ÿ… Unique Badges", value: `${ownedBadges.length}`, inline: true }, { name: "๐ŸŽฎ Games", value: [ `Played: **${stats.games.total.played}**`, `Won: **${stats.games.total.won}**`, `Lost: **${stats.games.total.lost}**`, `Pushes: **${stats.games.total.pushed}**` ].join("\n"), inline: true }, { name: "๐Ÿ”ฅ Best Streaks", value: [ `Wins: **${stats.streaks.bestWin}**`, `Losses: **${stats.streaks.bestLoss}**` ].join("\n"), inline: true } ) .setFooter({ text: `profile:${user.id}` }); } async function buildBadgesEmbed(guildId, user) { await ensureProfileSystem(); await ensureGuildBadges(guildId); const { badges } = getProfileCollections(); const documents = await badges.find({ guildId }).toArray(); const owned = documents.filter(badge => badge.ownerId === user.id); const other = documents.filter(badge => badge.ownerId && badge.ownerId !== user.id); const unclaimed = documents.filter(badge => !badge.ownerId); return new EmbedBuilder() .setTitle(`๐Ÿ… ${user.globalName ?? user.username}'s Badges`) .setDescription([ "### Owned", owned.length ? owned.map(b => `${b.emoji} **${b.name}**\n${b.description}`).join("\n\n") : "*No unique badges yet.*", "", "### Claimed by Others", other.length ? other.map(b => `${b.emoji} **${b.name}** โ€” <@${b.ownerId}>`).join("\n") : "*None yet.*", "", "### Still Available", unclaimed.length ? unclaimed.map(b => `${b.emoji} **${b.name}**\n${b.description}`).join("\n\n") : "*All unique badges have been claimed.*" ].join("\n")) .setFooter({ text: `profile:${user.id}` }); } async function buildAchievementsEmbed(guildId, user) { await ensureProfileSystem(); const { achievements, achievementConfig } = getProfileCollections(); const [unlockedDoc, definitions] = await Promise.all([ achievements.findOne({ userId: user.id, guildId }), achievementConfig.find({}).sort({ category: 1, target: 1 }).toArray() ]); const unlocked = unlockedDoc?.unlocked ?? {}; const stats = await getProfileStats(user.id, guildId); const lines = definitions.map(a => { const complete = Boolean(unlocked[a.achievementId]); const current = readStatValue(stats, a); const progress = complete ? "Unlocked" : `${Math.min(current, a.target).toLocaleString()} / ${a.target.toLocaleString()}`; return `${complete ? "โœ…" : "โฌœ"} ${a.emoji} **${a.name}** โ€” ${a.requirement}\nโ†ณ ${progress}`; }); return new EmbedBuilder() .setTitle(`๐Ÿ† ${user.globalName ?? user.username}'s Achievements`) .setDescription(lines.join("\n") || "No achievements configured.") .setFooter({ text: `profile:${user.id}` }); } async function buildStatsEmbed(guildId, user) { await ensureProfileSystem(); const stats = await getProfileStats(user.id, guildId); const e = stats.economy; const g = stats.games; return new EmbedBuilder() .setTitle(`๐Ÿ“Š ${user.globalName ?? user.username}'s Statistics`) .setThumbnail(user.displayAvatarURL({ size: 256 })) .addFields( { name: "๐Ÿช Economy", value: [ `Obtained: **${e.cookiesObtainedTotal.toLocaleString()}**`, `Lost: **${e.cookiesLostTotal.toLocaleString()}**`, `Given: **${e.cookiesGivenTotal.toLocaleString()}**`, `Stolen: **${e.stolenTotal.toLocaleString()}**`, `Stolen from you: **${e.stolenFromMeTotal.toLocaleString()}**`, `Bot Vault stolen: **${e.vaultStolenTotal.toLocaleString()}**` ].join("\n") }, { name: "๐Ÿฅท Theft", value: [ `Unique victims: **${stats.unique.playersStolenFrom.length}**`, `Unique thieves: **${stats.unique.playersStolenBy.length}**` ].join("\n"), inline: true }, { name: "๐Ÿ”ฅ Streaks", value: [ `Current wins: **${stats.streaks.currentWin}**`, `Best wins: **${stats.streaks.bestWin}**`, `Current losses: **${stats.streaks.currentLoss}**`, `Best losses: **${stats.streaks.bestLoss}**` ].join("\n"), inline: true }, { name: "๐ŸŽฐ Slots", value: formatGameStats(g.slots), inline: true }, { name: "๐Ÿƒ Blackjack", value: formatGameStats(g.blackjack), inline: true }, { name: "๐ŸŽก Roulette", value: formatGameStats(g.roulette), inline: true }, { name: "๐Ÿฆ Heist", value: formatGameStats(g.heist), inline: true } ) .setFooter({ text: `profile:${user.id}` }); } function formatGameStats(game) { return [ `Played: **${game?.played ?? 0}**`, `Won: **${game?.won ?? 0}**`, `Lost: **${game?.lost ?? 0}**`, `Pushes: **${game?.pushed ?? 0}**` ].join("\n"); } function buildProfileButtons() { return [ new ActionRowBuilder().addComponents( new ButtonBuilder().setCustomId("profileOverview").setLabel("Overview").setEmoji("๐Ÿ‘ค").setStyle(ButtonStyle.Primary), new ButtonBuilder().setCustomId("profileStats").setLabel("Stats").setEmoji("๐Ÿ“Š").setStyle(ButtonStyle.Secondary), new ButtonBuilder().setCustomId("profileBadges").setLabel("Badges").setEmoji("๐Ÿ…").setStyle(ButtonStyle.Secondary), new ButtonBuilder().setCustomId("profileAchievements").setLabel("Achievements").setEmoji("๐Ÿ†").setStyle(ButtonStyle.Secondary), new ButtonBuilder().setCustomId("abort").setLabel("Close").setEmoji("โœ–๏ธ").setStyle(ButtonStyle.Secondary) ) ]; } function getProfileTargetId(interaction) { const footer = interaction.message?.embeds?.[0]?.footer?.text; const [type, userId] = footer?.split(":") ?? []; return type === "profile" ? userId : null; } module.exports = { ensureProfileSystem, ensureGuildBadges, trackProfileEvent, getProfileStats, buildProfileOverview, buildStatsEmbed, buildBadgesEmbed, buildAchievementsEmbed, buildProfileButtons, getProfileTargetId };