clashroyale-bot/src/commands/sync.js
2025-10-18 08:14:08 +02:00

238 lines
10 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require('discord.js');
const { clashRoyaleAPI } = require('../services/clashRoyaleService');
const { UserProfileService } = require('../utils/database');
module.exports = {
data: new SlashCommandBuilder()
.setName('sync')
.setDescription('Associer votre profil Clash Royale à votre compte Discord')
.addStringOption(option =>
option
.setName('id')
.setDescription('Votre tag Clash Royale (ex: #ABC123DEF)')
.setRequired(true)
),
async execute(interaction, client) {
await interaction.deferReply({ ephemeral: true });
try {
// Vérification du rôle requis
const requiredRoleId = process.env.CLASH_ROYALE_ROLE_ID;
if (!interaction.member.roles.cache.has(requiredRoleId)) {
const errorEmbed = new EmbedBuilder()
.setColor('#FF0000')
.setTitle('❌ Accès refusé')
.setDescription('Vous devez avoir le rôle requis pour utiliser cette commande.')
.addFields([
{
name: 'Rôle requis',
value: `<@&${requiredRoleId}>`,
inline: true
}
])
.setTimestamp();
await interaction.editReply({ embeds: [errorEmbed] });
return;
}
const clashTag = interaction.options.getString('id');
const discordId = interaction.user.id;
client.logger.clash(`Tentative de synchronisation: ${interaction.user.tag} -> ${clashTag}`);
// Vérifier si l'utilisateur a déjà un profil synchronisé
const existingProfile = await UserProfileService.getByDiscordId(discordId);
// Vérifier si le tag Clash Royale est déjà utilisé par quelqu'un d'autre
const existingClashProfile = await UserProfileService.getByClashTag(clashTag);
if (existingClashProfile && existingClashProfile.discord_id !== discordId) {
const conflictEmbed = new EmbedBuilder()
.setColor('#FF6B00')
.setTitle('⚠️ Tag déjà utilisé')
.setDescription('Ce tag Clash Royale est déjà associé à un autre utilisateur Discord.')
.addFields([
{
name: 'Tag Clash Royale',
value: `\`${clashTag}\``,
inline: true
},
{
name: 'Solution',
value: 'Vérifiez que vous avez entré le bon tag ou contactez un administrateur.',
inline: false
}
])
.setTimestamp();
await interaction.editReply({ embeds: [conflictEmbed] });
return;
}
// Valider le profil Clash Royale via l'API
const validationResult = await clashRoyaleAPI.validatePlayer(clashTag);
if (!validationResult.valid) {
let errorMessage = 'Tag Clash Royale invalide ou joueur non trouvé.';
let errorTitle = '❌ Profil non trouvé';
switch (validationResult.error.type) {
case 'NOT_FOUND':
errorMessage = 'Aucun joueur trouvé avec ce tag. Vérifiez que vous avez entré le bon tag.';
break;
case 'BAD_REQUEST':
errorMessage = 'Format de tag invalide. Utilisez le format #ABC123DEF.';
break;
case 'RATE_LIMITED':
errorMessage = 'Trop de requêtes à l\'API. Réessayez dans quelques minutes.';
errorTitle = '⏳ Limite atteinte';
break;
case 'SERVICE_UNAVAILABLE':
errorMessage = 'API Clash Royale temporairement indisponible. Réessayez plus tard.';
errorTitle = '🛠️ Maintenance';
break;
}
const errorEmbed = new EmbedBuilder()
.setColor('#FF0000')
.setTitle(errorTitle)
.setDescription(errorMessage)
.addFields([
{
name: 'Tag fourni',
value: `\`${clashTag}\``,
inline: true
},
{
name: 'Aide',
value: 'Le tag se trouve dans votre profil Clash Royale, sous votre nom.',
inline: false
}
])
.setTimestamp();
await interaction.editReply({ embeds: [errorEmbed] });
return;
}
const playerData = validationResult.data;
// Créer ou mettre à jour le profil dans la base de données
const profile = await UserProfileService.createOrUpdate(discordId, playerData);
client.logger.success(`Profil synchronisé: ${playerData.name} (${playerData.tag})`);
// Déterminer si c'est une nouvelle synchronisation ou une mise à jour
const isNewSync = !existingProfile;
const actionText = isNewSync ? 'synchronisé' : 'mis à jour';
const actionEmoji = isNewSync ? '🎉' : '🔄';
// Créer l'embed de confirmation
const successEmbed = new EmbedBuilder()
.setColor('#00FF00')
.setTitle(`${actionEmoji} Profil ${actionText} avec succès !`)
.setDescription(`Votre compte Discord est maintenant associé à votre profil Clash Royale.`)
.setThumbnail(interaction.user.displayAvatarURL({ dynamic: true }))
.addFields([
{
name: '👤 Nom du joueur',
value: playerData.name,
inline: true
},
{
name: '🏷️ Tag Clash Royale',
value: `\`${playerData.tag}\``,
inline: true
},
{
name: '🏆 Trophées actuels',
value: `${playerData.trophies.toLocaleString()}`,
inline: true
},
{
name: '🥇 Meilleur score',
value: `${playerData.bestTrophies.toLocaleString()}`,
inline: true
},
{
name: '⭐ Niveau',
value: `${playerData.expLevel}`,
inline: true
},
{
name: '🏰 Clan',
value: playerData.clan ?
`${playerData.clan.name}\n\`${playerData.clan.tag}\`\n*${playerData.clan.role}*` :
'Aucun clan',
inline: true
}
])
.addFields([
{
name: '✨ Fonctionnalités disponibles',
value: '• Classement automatique du serveur\n• Félicitations pour les gains de trophées\n• Statistiques personnalisées\n• Comparaisons avec les autres membres',
inline: false
}
])
.setFooter({
text: `${isNewSync ? 'Première synchronisation' : 'Profile mis à jour'} • Clash Royale Bot`,
iconURL: client.user.displayAvatarURL()
})
.setTimestamp();
await interaction.editReply({ embeds: [successEmbed] });
// Log dans le canal de logs si configuré
try {
const logChannel = client.channels.cache.get(process.env.LOGS_CHANNEL_ID);
if (logChannel) {
const logEmbed = new EmbedBuilder()
.setColor('#00BFFF')
.setTitle('📊 Nouvelle synchronisation')
.setDescription(`Un utilisateur a ${actionText} son profil Clash Royale`)
.addFields([
{
name: 'Utilisateur Discord',
value: `${interaction.user.tag} (<@${interaction.user.id}>)`,
inline: true
},
{
name: 'Joueur Clash Royale',
value: `${playerData.name} (\`${playerData.tag}\`)`,
inline: true
},
{
name: 'Trophées',
value: `${playerData.trophies.toLocaleString()}`,
inline: true
}
])
.setTimestamp();
await logChannel.send({ embeds: [logEmbed] });
}
} catch (error) {
client.logger.warning('Impossible d\'envoyer le log de synchronisation');
}
} catch (error) {
client.logger.error(`Erreur lors de la synchronisation: ${error.message}`);
const errorEmbed = new EmbedBuilder()
.setColor('#FF0000')
.setTitle('❌ Erreur interne')
.setDescription('Une erreur s\'est produite lors de la synchronisation. Veuillez réessayer.')
.addFields([
{
name: 'Code d\'erreur',
value: `\`${error.message}\``,
inline: false
}
])
.setTimestamp();
await interaction.editReply({ embeds: [errorEmbed] });
}
}
};