const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); const { getServerMode, EMBED_COLORS } = require('../utils/modeHelper'); const { getStandaloneXp, prestigeStandalone, calculateLevel } = require('../utils/standaloneXp'); module.exports = { data: new SlashCommandBuilder() .setName('prestige') .setDescription('Prestige system - reset your level for permanent rewards') .addSubcommand(sub => sub.setName('view') .setDescription('View your prestige status and rewards') .addUserOption(opt => opt.setName('user') .setDescription('User to check') .setRequired(false) ) ) .addSubcommand(sub => sub.setName('up') .setDescription('Prestige up! Reset your XP for permanent rewards') ) .addSubcommand(sub => sub.setName('rewards') .setDescription('View all prestige rewards') ), async execute(interaction, supabase, client) { if (!supabase) { return interaction.reply({ content: 'Database not configured.', ephemeral: true }); } const sub = interaction.options.getSubcommand(); const mode = await getServerMode(supabase, interaction.guildId); if (sub === 'view') { return viewPrestige(interaction, supabase, mode); } else if (sub === 'up') { return prestigeUp(interaction, supabase, client, mode); } else if (sub === 'rewards') { return viewRewards(interaction, mode); } }, }; async function viewPrestige(interaction, supabase, mode) { const target = interaction.options.getUser('user') || interaction.user; await interaction.deferReply(); try { if (mode === 'standalone') { const data = await getStandaloneXp(supabase, target.id, interaction.guildId); if (!data) { return interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(EMBED_COLORS.standalone) .setDescription(`${target.id === interaction.user.id ? 'You have' : `${target.tag} has`} no XP data yet.`) ] }); } const prestige = data.prestige_level || 0; const currentXp = data.xp || 0; const totalXpEarned = data.total_xp_earned || currentXp; const level = calculateLevel(currentXp, 'normal'); const prestigeInfo = getPrestigeInfo(prestige); const canPrestige = level >= 50; const embed = new EmbedBuilder() .setColor(prestigeInfo.color) .setTitle(`${prestigeInfo.icon} ${target.tag}'s Prestige`) .setThumbnail(target.displayAvatarURL({ size: 256 })) .addFields( { name: 'Prestige Level', value: `**${prestigeInfo.name}** (${prestige})`, inline: true }, { name: 'XP Bonus', value: `+${prestige * 5}%`, inline: true }, { name: 'Current Level', value: `${level}`, inline: true }, { name: 'Total XP Earned', value: totalXpEarned.toLocaleString(), inline: true }, { name: 'Current XP', value: currentXp.toLocaleString(), inline: true }, { name: 'Can Prestige?', value: canPrestige ? 'Yes (Level 50+)' : `Need Level 50 (${level}/50)`, inline: true } ) .setFooter({ text: `🏠 Standalone Mode • ${interaction.guild.name}` }) .setTimestamp(); if (prestige > 0) { embed.addFields({ name: 'Prestige Rewards Unlocked', value: getUnlockedRewards(prestige).join('\n') || 'None yet', inline: false }); } return interaction.editReply({ embeds: [embed] }); } const { data: link } = await supabase .from('discord_links') .select('user_id') .eq('discord_id', target.id) .maybeSingle(); if (!link) { return interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(0xff6b6b) .setDescription(`${target.id === interaction.user.id ? 'You are' : `${target.tag} is`} not linked to AeThex.`) ] }); } const { data: profile } = await supabase .from('user_profiles') .select('username, xp, prestige_level, total_xp_earned') .eq('id', link.user_id) .maybeSingle(); const prestige = profile?.prestige_level || 0; const totalXpEarned = profile?.total_xp_earned || profile?.xp || 0; const currentXp = profile?.xp || 0; const level = Math.floor(Math.sqrt(currentXp / 100)); const prestigeInfo = getPrestigeInfo(prestige); const canPrestige = level >= 50; const embed = new EmbedBuilder() .setColor(prestigeInfo.color) .setTitle(`${prestigeInfo.icon} ${profile?.username || target.tag}'s Prestige`) .setThumbnail(target.displayAvatarURL({ size: 256 })) .addFields( { name: 'Prestige Level', value: `**${prestigeInfo.name}** (${prestige})`, inline: true }, { name: 'XP Bonus', value: `+${prestige * 5}%`, inline: true }, { name: 'Current Level', value: `${level}`, inline: true }, { name: 'Total XP Earned', value: totalXpEarned.toLocaleString(), inline: true }, { name: 'Current XP', value: currentXp.toLocaleString(), inline: true }, { name: 'Can Prestige?', value: canPrestige ? 'Yes (Level 50+)' : `Need Level 50 (${level}/50)`, inline: true } ) .setFooter({ text: `🌐 Federation • Next prestige requirement: Level 50` }) .setTimestamp(); if (prestige > 0) { embed.addFields({ name: 'Prestige Rewards Unlocked', value: getUnlockedRewards(prestige).join('\n') || 'None yet', inline: false }); } await interaction.editReply({ embeds: [embed] }); } catch (error) { console.error('Prestige view error:', error); await interaction.editReply({ content: 'Failed to fetch prestige data.' }); } } async function prestigeUp(interaction, supabase, client, mode) { await interaction.deferReply(); try { if (mode === 'standalone') { const data = await getStandaloneXp(supabase, interaction.user.id, interaction.guildId); if (!data) { return interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(EMBED_COLORS.error) .setDescription('You have no XP data yet. Start chatting to earn XP!') ] }); } const currentXp = data.xp || 0; const level = calculateLevel(currentXp, 'normal'); const prestige = data.prestige_level || 0; if (level < 50) { return interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(EMBED_COLORS.error) .setTitle('Cannot Prestige') .setDescription(`You need to reach **Level 50** to prestige.\nCurrent level: **${level}**/50`) ] }); } if (prestige >= 10) { return interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(0xffd700) .setTitle('Maximum Prestige!') .setDescription('You have reached the maximum prestige level!') ] }); } const newPrestige = prestige + 1; const newPrestigeInfo = getPrestigeInfo(newPrestige); const confirmEmbed = new EmbedBuilder() .setColor(EMBED_COLORS.warning) .setTitle('Confirm Prestige') .setDescription(`Are you sure you want to prestige?\n\n**What will happen:**\n• Your XP will reset to **0**\n• Your level will reset to **0**\n• You gain **Prestige ${newPrestige}** (${newPrestigeInfo.name})\n• You get a permanent **+${newPrestige * 5}%** XP bonus\n\n**Current Stats:**\n• Level: ${level}\n• XP: ${currentXp.toLocaleString()}`) .setFooter({ text: 'This action cannot be undone!' }); const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() .setCustomId('prestige_confirm_standalone') .setLabel('Prestige Up!') .setStyle(ButtonStyle.Success), new ButtonBuilder() .setCustomId('prestige_cancel_standalone') .setLabel('Cancel') .setStyle(ButtonStyle.Secondary) ); const response = await interaction.editReply({ embeds: [confirmEmbed], components: [row] }); try { const confirmation = await response.awaitMessageComponent({ filter: i => i.user.id === interaction.user.id, time: 60000 }); if (confirmation.customId === 'prestige_confirm_standalone') { const result = await prestigeStandalone(supabase, interaction.user.id, interaction.guildId); if (!result.success) { return confirmation.update({ embeds: [ new EmbedBuilder() .setColor(EMBED_COLORS.error) .setDescription(result.message) ], components: [] }); } const successEmbed = new EmbedBuilder() .setColor(newPrestigeInfo.color) .setTitle(`${newPrestigeInfo.icon} Prestige ${result.newPrestige} Achieved!`) .setDescription(`Congratulations! You are now **${newPrestigeInfo.name}**!`) .addFields( { name: 'XP Bonus', value: `+${result.bonus}%`, inline: true } ) .setThumbnail(interaction.user.displayAvatarURL({ size: 256 })) .setFooter({ text: '🏠 Standalone Mode' }) .setTimestamp(); await confirmation.update({ embeds: [successEmbed], components: [] }); } else { await confirmation.update({ embeds: [ new EmbedBuilder() .setColor(EMBED_COLORS.standalone) .setDescription('Prestige cancelled.') ], components: [] }); } } catch (e) { await interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(EMBED_COLORS.standalone) .setDescription('Prestige request timed out.') ], components: [] }); } return; } const { data: link } = await supabase .from('discord_links') .select('user_id') .eq('discord_id', interaction.user.id) .single(); if (!link) { return interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(0xff6b6b) .setDescription('You must link your Discord to AeThex first. Use `/verify` to link.') ] }); } const { data: profile } = await supabase .from('user_profiles') .select('username, xp, prestige_level, total_xp_earned') .eq('id', link.user_id) .maybeSingle(); const currentXp = profile?.xp || 0; const level = Math.floor(Math.sqrt(currentXp / 100)); const prestige = profile?.prestige_level || 0; const totalEarned = profile?.total_xp_earned || currentXp; if (level < 50) { return interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(0xff6b6b) .setTitle('Cannot Prestige') .setDescription(`You need to reach **Level 50** to prestige.\nCurrent level: **${level}**/50`) ] }); } if (prestige >= 10) { return interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(0xffd700) .setTitle('Maximum Prestige!') .setDescription('You have reached the maximum prestige level! You are a true legend.') ] }); } const newPrestige = prestige + 1; const newPrestigeInfo = getPrestigeInfo(newPrestige); const xpBonus = newPrestige * 5; const confirmEmbed = new EmbedBuilder() .setColor(0xf59e0b) .setTitle('Confirm Prestige') .setDescription(`Are you sure you want to prestige?\n\n**What will happen:**\n• Your XP will reset to **0**\n• Your level will reset to **0**\n• You gain **Prestige ${newPrestige}** (${newPrestigeInfo.name})\n• You get a permanent **+${xpBonus}%** XP bonus\n• You unlock new **prestige rewards**\n\n**Current Stats:**\n• Level: ${level}\n• XP: ${currentXp.toLocaleString()}`) .setFooter({ text: 'This action cannot be undone!' }); const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() .setCustomId('prestige_confirm') .setLabel('Prestige Up!') .setStyle(ButtonStyle.Success), new ButtonBuilder() .setCustomId('prestige_cancel') .setLabel('Cancel') .setStyle(ButtonStyle.Secondary) ); const response = await interaction.editReply({ embeds: [confirmEmbed], components: [row] }); try { const confirmation = await response.awaitMessageComponent({ filter: i => i.user.id === interaction.user.id, time: 60000 }); if (confirmation.customId === 'prestige_confirm') { const { error } = await supabase .from('user_profiles') .update({ xp: 0, prestige_level: newPrestige }) .eq('id', link.user_id); if (error) { console.error('Prestige update error:', error); return confirmation.update({ embeds: [ new EmbedBuilder() .setColor(0xff0000) .setDescription('Failed to prestige. Please try again.') ], components: [] }); } const successEmbed = new EmbedBuilder() .setColor(newPrestigeInfo.color) .setTitle(`${newPrestigeInfo.icon} Prestige ${newPrestige} Achieved!`) .setDescription(`Congratulations! You are now **${newPrestigeInfo.name}**!\n\n**Rewards Unlocked:**\n${getNewRewards(newPrestige).join('\n')}`) .addFields( { name: 'XP Bonus', value: `+${xpBonus}%`, inline: true }, { name: 'Total XP Earned (All Time)', value: totalEarned.toLocaleString(), inline: true } ) .setThumbnail(interaction.user.displayAvatarURL({ size: 256 })) .setFooter({ text: '🌐 Federation' }) .setTimestamp(); await confirmation.update({ embeds: [successEmbed], components: [] }); } else { await confirmation.update({ embeds: [ new EmbedBuilder() .setColor(0x6b7280) .setDescription('Prestige cancelled.') ], components: [] }); } } catch (e) { await interaction.editReply({ embeds: [ new EmbedBuilder() .setColor(0x6b7280) .setDescription('Prestige request timed out.') ], components: [] }); } } catch (error) { console.error('Prestige up error:', error); await interaction.editReply({ content: 'Failed to process prestige.' }); } } async function viewRewards(interaction, mode) { const embed = new EmbedBuilder() .setColor(mode === 'standalone' ? EMBED_COLORS.standalone : 0x7c3aed) .setTitle('Prestige Rewards') .setDescription('Each prestige level grants permanent rewards!\n\n**Requirements:** Level 50 to prestige') .addFields( { name: 'Prestige 1 - Bronze', value: '+5% XP bonus\nBronze Prestige badge', inline: true }, { name: 'Prestige 2 - Silver', value: '+10% XP bonus\nSilver Prestige badge', inline: true }, { name: 'Prestige 3 - Gold', value: '+15% XP bonus\nGold Prestige badge', inline: true }, { name: 'Prestige 4 - Platinum', value: '+20% XP bonus\nPlatinum badge\nBonus daily XP', inline: true }, { name: 'Prestige 5 - Diamond', value: '+25% XP bonus\nDiamond badge\nReduced cooldowns', inline: true }, { name: 'Prestige 6 - Master', value: '+30% XP bonus\nMaster badge\nXP milestone rewards', inline: true }, { name: 'Prestige 7 - Grandmaster', value: '+35% XP bonus\nGrandmaster badge\nSpecial profile effects', inline: true }, { name: 'Prestige 8 - Champion', value: '+40% XP bonus\nChampion badge\nLeaderboard priority', inline: true }, { name: 'Prestige 9 - Legend', value: '+45% XP bonus\nLegend badge\nLegendary profile aura', inline: true }, { name: 'Prestige 10 - Mythic', value: '+50% XP bonus\nMythic badge\nAll prestige perks!', inline: true } ) .setFooter({ text: `${mode === 'standalone' ? '🏠 Standalone' : '🌐 Federation'} • Use /prestige up when you reach Level 50!` }) .setTimestamp(); await interaction.reply({ embeds: [embed] }); } function getPrestigeInfo(level) { const prestiges = [ { name: 'Unprestiged', icon: '', color: 0x6b7280 }, { name: 'Bronze', icon: '', color: 0xcd7f32 }, { name: 'Silver', icon: '', color: 0xc0c0c0 }, { name: 'Gold', icon: '', color: 0xffd700 }, { name: 'Platinum', icon: '', color: 0xe5e4e2 }, { name: 'Diamond', icon: '', color: 0xb9f2ff }, { name: 'Master', icon: '', color: 0xff4500 }, { name: 'Grandmaster', icon: '', color: 0x9400d3 }, { name: 'Champion', icon: '', color: 0xffd700 }, { name: 'Legend', icon: '', color: 0xff69b4 }, { name: 'Mythic', icon: '', color: 0x7c3aed } ]; return prestiges[Math.min(level, 10)] || prestiges[0]; } function getUnlockedRewards(prestige) { const rewards = []; if (prestige >= 1) rewards.push('Bronze Prestige badge'); if (prestige >= 2) rewards.push('Silver Prestige badge'); if (prestige >= 3) rewards.push('Gold Prestige badge'); if (prestige >= 4) rewards.push('Platinum badge + Bonus daily XP'); if (prestige >= 5) rewards.push('Diamond badge + Reduced cooldowns'); if (prestige >= 6) rewards.push('Master badge + XP milestones'); if (prestige >= 7) rewards.push('Grandmaster badge + Profile effects'); if (prestige >= 8) rewards.push('Champion badge + Leaderboard priority'); if (prestige >= 9) rewards.push('Legend badge + Legendary aura'); if (prestige >= 10) rewards.push('Mythic badge + All perks unlocked'); return rewards; } function getNewRewards(prestige) { const rewardMap = { 1: ['Bronze Prestige badge', '+5% XP bonus on all XP gains'], 2: ['Silver Prestige badge', '+10% XP bonus on all XP gains'], 3: ['Gold Prestige badge', '+15% XP bonus on all XP gains'], 4: ['Platinum badge', '+20% XP bonus', '+25 bonus daily XP'], 5: ['Diamond badge', '+25% XP bonus', '10% reduced XP cooldowns'], 6: ['Master badge', '+30% XP bonus', 'XP milestone rewards'], 7: ['Grandmaster badge', '+35% XP bonus', 'Special profile effects'], 8: ['Champion badge', '+40% XP bonus', 'Leaderboard priority display'], 9: ['Legend badge', '+45% XP bonus', 'Legendary profile aura'], 10: ['Mythic badge', '+50% XP bonus', 'All prestige perks unlocked!'] }; return rewardMap[prestige] || []; }