const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('backup')
    .setDescription('Server backup and restore system')
    .setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
    .addSubcommand(subcommand =>
      subcommand
        .setName('create')
        .setDescription('Create a backup of server configuration')
        .addStringOption(option =>
          option.setName('name')
            .setDescription('Name for this backup')
            .setRequired(false)
        )
        .addStringOption(option =>
          option.setName('description')
            .setDescription('Description of this backup')
            .setRequired(false)
        )
    )
    .addSubcommand(subcommand =>
      subcommand
        .setName('list')
        .setDescription('List all available backups')
    )
    .addSubcommand(subcommand =>
      subcommand
        .setName('view')
        .setDescription('View details of a specific backup')
        .addStringOption(option =>
          option.setName('id')
            .setDescription('Backup ID to view')
            .setRequired(true)
        )
    )
    .addSubcommand(subcommand =>
      subcommand
        .setName('restore')
        .setDescription('Restore from a backup')
        .addStringOption(option =>
          option.setName('id')
            .setDescription('Backup ID to restore')
            .setRequired(true)
        )
        .addStringOption(option =>
          option.setName('components')
            .setDescription('What to restore')
            .setRequired(false)
            .addChoices(
              { name: 'Everything', value: 'all' },
              { name: 'Roles Only', value: 'roles' },
              { name: 'Channels Only', value: 'channels' },
              { name: 'Bot Config Only', value: 'bot_config' }
            )
        )
    )
    .addSubcommand(subcommand =>
      subcommand
        .setName('delete')
        .setDescription('Delete a backup')
        .addStringOption(option =>
          option.setName('id')
            .setDescription('Backup ID to delete')
            .setRequired(true)
        )
    )
    .addSubcommand(subcommand =>
      subcommand
        .setName('auto')
        .setDescription('Configure automatic backups')
        .addBooleanOption(option =>
          option.setName('enabled')
            .setDescription('Enable or disable auto backups')
            .setRequired(true)
        )
        .addIntegerOption(option =>
          option.setName('interval')
            .setDescription('Backup interval in hours (default: 24)')
            .setRequired(false)
            .setMinValue(1)
            .setMaxValue(168)
        )
        .addIntegerOption(option =>
          option.setName('keep')
            .setDescription('Number of backups to keep (default: 7)')
            .setRequired(false)
            .setMinValue(1)
            .setMaxValue(30)
        )
    )
    .addSubcommand(subcommand =>
      subcommand
        .setName('compare')
        .setDescription('Compare current server state with a backup')
        .addStringOption(option =>
          option.setName('id')
            .setDescription('Backup ID to compare against')
            .setRequired(true)
        )
    ),

  async execute(interaction, supabase, client) {
    const subcommand = interaction.options.getSubcommand();

    if (!supabase) {
      const embed = new EmbedBuilder()
        .setColor(0xff0000)
        .setTitle('Database Not Connected')
        .setDescription('Backup system requires database connection.')
        .setTimestamp();
      return interaction.reply({ embeds: [embed], ephemeral: true });
    }

    if (subcommand === 'create') {
      await interaction.deferReply();
      
      const backupName = interaction.options.getString('name') || `Backup ${new Date().toLocaleDateString()}`;
      const description = interaction.options.getString('description') || 'Manual backup';
      
      try {
        const backupData = await createBackup(interaction.guild, supabase, interaction.guildId);
        
        const { data: backup, error } = await supabase.from('server_backups').insert({
          guild_id: interaction.guildId,
          name: backupName,
          description: description,
          backup_type: 'manual',
          created_by: interaction.user.id,
          data: backupData,
          roles_count: backupData.roles?.length || 0,
          channels_count: backupData.channels?.length || 0,
          size_bytes: JSON.stringify(backupData).length
        }).select().single();
        
        if (error) throw error;
        
        const embed = new EmbedBuilder()
          .setColor(0x00ff00)
          .setTitle('Backup Created Successfully')
          .setDescription(`Your server configuration has been saved.`)
          .addFields(
            { name: 'Backup ID', value: `\`${backup.id}\``, inline: true },
            { name: 'Name', value: backupName, inline: true },
            { name: 'Created By', value: `<@${interaction.user.id}>`, inline: true },
            { name: 'Roles Saved', value: `${backupData.roles?.length || 0}`, inline: true },
            { name: 'Channels Saved', value: `${backupData.channels?.length || 0}`, inline: true },
            { name: 'Size', value: formatBytes(backup.size_bytes), inline: true }
          )
          .setFooter({ text: `Use /backup restore id:${backup.id} to restore` })
          .setTimestamp();
        
        await interaction.editReply({ embeds: [embed] });
      } catch (error) {
        console.error('Backup creation error:', error);
        const embed = new EmbedBuilder()
          .setColor(0xff0000)
          .setTitle('Backup Failed')
          .setDescription(`Failed to create backup: ${error.message}`)
          .setTimestamp();
        await interaction.editReply({ embeds: [embed] });
      }
    }
    
    else if (subcommand === 'list') {
      try {
        const { data: backups, error } = await supabase
          .from('server_backups')
          .select('id, name, description, backup_type, created_at, created_by, roles_count, channels_count, size_bytes')
          .eq('guild_id', interaction.guildId)
          .order('created_at', { ascending: false })
          .limit(15);
        
        if (error) throw error;
        
        if (!backups || backups.length === 0) {
          const embed = new EmbedBuilder()
            .setColor(0xffa500)
            .setTitle('No Backups Found')
            .setDescription('This server has no backups. Create one with `/backup create`')
            .setTimestamp();
          return interaction.reply({ embeds: [embed] });
        }
        
        const backupList = backups.map((b, i) => {
          const date = new Date(b.created_at).toLocaleDateString();
          const typeIcon = b.backup_type === 'auto' ? '🔄' : '📁';
          return `${typeIcon} **${b.name}**\n> ID: \`${b.id}\` | ${date} | ${b.roles_count} roles, ${b.channels_count} channels`;
        }).join('\n\n');
        
        const embed = new EmbedBuilder()
          .setColor(0x7c3aed)
          .setTitle(`Server Backups (${backups.length})`)
          .setDescription(backupList)
          .setFooter({ text: 'Use /backup view id:<id> for details' })
          .setTimestamp();
        
        await interaction.reply({ embeds: [embed] });
      } catch (error) {
        console.error('List backups error:', error);
        const embed = new EmbedBuilder()
          .setColor(0xff0000)
          .setTitle('Error')
          .setDescription('Failed to list backups.')
          .setTimestamp();
        await interaction.reply({ embeds: [embed], ephemeral: true });
      }
    }
    
    else if (subcommand === 'view') {
      const backupId = interaction.options.getString('id');
      
      try {
        const { data: backup, error } = await supabase
          .from('server_backups')
          .select('*')
          .eq('id', backupId)
          .eq('guild_id', interaction.guildId)
          .single();
        
        if (error || !backup) {
          const embed = new EmbedBuilder()
            .setColor(0xff0000)
            .setTitle('Backup Not Found')
            .setDescription('Could not find a backup with that ID for this server.')
            .setTimestamp();
          return interaction.reply({ embeds: [embed], ephemeral: true });
        }
        
        const data = backup.data;
        const rolesPreview = data.roles?.slice(0, 5).map(r => r.name).join(', ') || 'None';
        const channelsPreview = data.channels?.slice(0, 5).map(c => `#${c.name}`).join(', ') || 'None';
        
        const embed = new EmbedBuilder()
          .setColor(0x7c3aed)
          .setTitle(`Backup: ${backup.name}`)
          .setDescription(backup.description || 'No description')
          .addFields(
            { name: 'Backup ID', value: `\`${backup.id}\``, inline: true },
            { name: 'Type', value: backup.backup_type === 'auto' ? '🔄 Automatic' : '📁 Manual', inline: true },
            { name: 'Created', value: `<t:${Math.floor(new Date(backup.created_at).getTime() / 1000)}:R>`, inline: true },
            { name: 'Created By', value: backup.created_by ? `<@${backup.created_by}>` : 'System', inline: true },
            { name: 'Size', value: formatBytes(backup.size_bytes), inline: true },
            { name: '\u200b', value: '\u200b', inline: true },
            { name: `Roles (${backup.roles_count})`, value: rolesPreview + (data.roles?.length > 5 ? '...' : ''), inline: false },
            { name: `Channels (${backup.channels_count})`, value: channelsPreview + (data.channels?.length > 5 ? '...' : ''), inline: false }
          )
          .setFooter({ text: `Use /backup restore id:${backup.id} to restore` })
          .setTimestamp();
        
        const row = new ActionRowBuilder().addComponents(
          new ButtonBuilder()
            .setCustomId(`backup_restore_${backup.id}`)
            .setLabel('Restore This Backup')
            .setStyle(ButtonStyle.Primary)
            .setEmoji('🔄'),
          new ButtonBuilder()
            .setCustomId(`backup_delete_${backup.id}`)
            .setLabel('Delete')
            .setStyle(ButtonStyle.Danger)
            .setEmoji('🗑️')
        );
        
        await interaction.reply({ embeds: [embed], components: [row] });
      } catch (error) {
        console.error('View backup error:', error);
        const embed = new EmbedBuilder()
          .setColor(0xff0000)
          .setTitle('Error')
          .setDescription('Failed to view backup.')
          .setTimestamp();
        await interaction.reply({ embeds: [embed], ephemeral: true });
      }
    }
    
    else if (subcommand === 'restore') {
      const backupId = interaction.options.getString('id');
      const components = interaction.options.getString('components') || 'all';
      
      try {
        const { data: backup, error } = await supabase
          .from('server_backups')
          .select('*')
          .eq('id', backupId)
          .eq('guild_id', interaction.guildId)
          .single();
        
        if (error || !backup) {
          const embed = new EmbedBuilder()
            .setColor(0xff0000)
            .setTitle('Backup Not Found')
            .setDescription('Could not find a backup with that ID for this server.')
            .setTimestamp();
          return interaction.reply({ embeds: [embed], ephemeral: true });
        }
        
        const confirmEmbed = new EmbedBuilder()
          .setColor(0xffa500)
          .setTitle('⚠️ Confirm Restore')
          .setDescription(`Are you sure you want to restore from **${backup.name}**?\n\nThis will restore: **${components === 'all' ? 'Everything' : components}**\n\n**Warning:** This action may modify your server's roles and channels. A new backup will be created first.`)
          .addFields(
            { name: 'Backup Date', value: `<t:${Math.floor(new Date(backup.created_at).getTime() / 1000)}:F>`, inline: true },
            { name: 'Components', value: components, inline: true }
          )
          .setTimestamp();
        
        const row = new ActionRowBuilder().addComponents(
          new ButtonBuilder()
            .setCustomId(`backup_confirm_restore_${backupId}_${components}`)
            .setLabel('Yes, Restore')
            .setStyle(ButtonStyle.Danger)
            .setEmoji('✅'),
          new ButtonBuilder()
            .setCustomId('backup_cancel_restore')
            .setLabel('Cancel')
            .setStyle(ButtonStyle.Secondary)
        );
        
        await interaction.reply({ embeds: [confirmEmbed], components: [row], ephemeral: true });
      } catch (error) {
        console.error('Restore backup error:', error);
        const embed = new EmbedBuilder()
          .setColor(0xff0000)
          .setTitle('Error')
          .setDescription('Failed to initiate restore.')
          .setTimestamp();
        await interaction.reply({ embeds: [embed], ephemeral: true });
      }
    }
    
    else if (subcommand === 'delete') {
      const backupId = interaction.options.getString('id');
      
      try {
        const { data: backup, error: fetchError } = await supabase
          .from('server_backups')
          .select('id, name')
          .eq('id', backupId)
          .eq('guild_id', interaction.guildId)
          .single();
        
        if (fetchError || !backup) {
          const embed = new EmbedBuilder()
            .setColor(0xff0000)
            .setTitle('Backup Not Found')
            .setDescription('Could not find a backup with that ID for this server.')
            .setTimestamp();
          return interaction.reply({ embeds: [embed], ephemeral: true });
        }
        
        const { error: deleteError } = await supabase
          .from('server_backups')
          .delete()
          .eq('id', backupId);
        
        if (deleteError) throw deleteError;
        
        const embed = new EmbedBuilder()
          .setColor(0x00ff00)
          .setTitle('Backup Deleted')
          .setDescription(`Successfully deleted backup: **${backup.name}**`)
          .setTimestamp();
        
        await interaction.reply({ embeds: [embed] });
      } catch (error) {
        console.error('Delete backup error:', error);
        const embed = new EmbedBuilder()
          .setColor(0xff0000)
          .setTitle('Error')
          .setDescription('Failed to delete backup.')
          .setTimestamp();
        await interaction.reply({ embeds: [embed], ephemeral: true });
      }
    }
    
    else if (subcommand === 'auto') {
      const enabled = interaction.options.getBoolean('enabled');
      const interval = interaction.options.getInteger('interval') || 24;
      const keep = interaction.options.getInteger('keep') || 7;
      
      try {
        await supabase.from('backup_settings').upsert({
          guild_id: interaction.guildId,
          auto_enabled: enabled,
          interval_hours: interval,
          max_backups: keep,
          updated_at: new Date().toISOString(),
          updated_by: interaction.user.id
        });
        
        const embed = new EmbedBuilder()
          .setColor(enabled ? 0x00ff00 : 0xffa500)
          .setTitle(`Auto Backups ${enabled ? 'Enabled' : 'Disabled'}`)
          .setDescription(enabled 
            ? `Automatic backups are now **enabled** for this server.`
            : `Automatic backups have been **disabled**.`
          )
          .setTimestamp();
        
        if (enabled) {
          embed.addFields(
            { name: 'Interval', value: `Every ${interval} hour${interval === 1 ? '' : 's'}`, inline: true },
            { name: 'Backups Kept', value: `${keep}`, inline: true }
          );
        }
        
        await interaction.reply({ embeds: [embed] });
      } catch (error) {
        console.error('Auto backup settings error:', error);
        const embed = new EmbedBuilder()
          .setColor(0xff0000)
          .setTitle('Error')
          .setDescription('Failed to update auto backup settings.')
          .setTimestamp();
        await interaction.reply({ embeds: [embed], ephemeral: true });
      }
    }
    
    else if (subcommand === 'compare') {
      await interaction.deferReply();
      const backupId = interaction.options.getString('id');
      
      try {
        const { data: backup, error } = await supabase
          .from('server_backups')
          .select('*')
          .eq('id', backupId)
          .eq('guild_id', interaction.guildId)
          .single();
        
        if (error || !backup) {
          const embed = new EmbedBuilder()
            .setColor(0xff0000)
            .setTitle('Backup Not Found')
            .setDescription('Could not find a backup with that ID for this server.')
            .setTimestamp();
          return interaction.editReply({ embeds: [embed] });
        }
        
        const currentData = await createBackup(interaction.guild, supabase, interaction.guildId);
        const backupData = backup.data;
        
        const currentRoleNames = new Set(currentData.roles.map(r => r.name));
        const backupRoleNames = new Set(backupData.roles?.map(r => r.name) || []);
        const addedRoles = currentData.roles.filter(r => !backupRoleNames.has(r.name)).map(r => r.name);
        const removedRoles = (backupData.roles || []).filter(r => !currentRoleNames.has(r.name)).map(r => r.name);
        
        const currentChannelNames = new Set(currentData.channels.map(c => c.name));
        const backupChannelNames = new Set(backupData.channels?.map(c => c.name) || []);
        const addedChannels = currentData.channels.filter(c => !backupChannelNames.has(c.name)).map(c => `#${c.name}`);
        const removedChannels = (backupData.channels || []).filter(c => !currentChannelNames.has(c.name)).map(c => `#${c.name}`);
        
        const embed = new EmbedBuilder()
          .setColor(0x7c3aed)
          .setTitle(`Comparison: ${backup.name}`)
          .setDescription(`Comparing current server state against backup from <t:${Math.floor(new Date(backup.created_at).getTime() / 1000)}:R>`)
          .addFields(
            { name: '➕ Roles Added Since Backup', value: addedRoles.length > 0 ? addedRoles.slice(0, 10).join(', ') + (addedRoles.length > 10 ? '...' : '') : 'None', inline: false },
            { name: '➖ Roles Removed Since Backup', value: removedRoles.length > 0 ? removedRoles.slice(0, 10).join(', ') + (removedRoles.length > 10 ? '...' : '') : 'None', inline: false },
            { name: '➕ Channels Added', value: addedChannels.length > 0 ? addedChannels.slice(0, 10).join(', ') + (addedChannels.length > 10 ? '...' : '') : 'None', inline: false },
            { name: '➖ Channels Removed', value: removedChannels.length > 0 ? removedChannels.slice(0, 10).join(', ') + (removedChannels.length > 10 ? '...' : '') : 'None', inline: false }
          )
          .setFooter({ text: 'Note: Permission and setting changes are not shown in this comparison' })
          .setTimestamp();
        
        await interaction.editReply({ embeds: [embed] });
      } catch (error) {
        console.error('Compare backup error:', error);
        const embed = new EmbedBuilder()
          .setColor(0xff0000)
          .setTitle('Error')
          .setDescription('Failed to compare backup.')
          .setTimestamp();
        await interaction.editReply({ embeds: [embed] });
      }
    }
  }
};

async function createBackup(guild, supabase, guildId) {
  const roles = guild.roles.cache
    .filter(r => !r.managed && r.id !== guild.id)
    .map(role => ({
      id: role.id,
      name: role.name,
      color: role.color,
      hoist: role.hoist,
      position: role.position,
      permissions: role.permissions.bitfield.toString(),
      mentionable: role.mentionable
    }))
    .sort((a, b) => b.position - a.position);
  
  const channels = guild.channels.cache
    .filter(c => c.type !== 4)
    .map(channel => ({
      id: channel.id,
      name: channel.name,
      type: channel.type,
      position: channel.position,
      parentId: channel.parentId,
      topic: channel.topic || null,
      nsfw: channel.nsfw || false,
      rateLimitPerUser: channel.rateLimitPerUser || 0,
      permissionOverwrites: channel.permissionOverwrites?.cache.map(po => ({
        id: po.id,
        type: po.type,
        allow: po.allow.bitfield.toString(),
        deny: po.deny.bitfield.toString()
      })) || []
    }))
    .sort((a, b) => a.position - b.position);
  
  const categories = guild.channels.cache
    .filter(c => c.type === 4)
    .map(cat => ({
      id: cat.id,
      name: cat.name,
      position: cat.position,
      permissionOverwrites: cat.permissionOverwrites?.cache.map(po => ({
        id: po.id,
        type: po.type,
        allow: po.allow.bitfield.toString(),
        deny: po.deny.bitfield.toString()
      })) || []
    }))
    .sort((a, b) => a.position - b.position);
  
  let botConfig = null;
  if (supabase) {
    const { data } = await supabase
      .from('server_config')
      .select('*')
      .eq('guild_id', guildId)
      .single();
    botConfig = data;
  }
  
  let levelRoles = [];
  if (supabase) {
    const { data } = await supabase
      .from('level_roles')
      .select('*')
      .eq('guild_id', guildId);
    levelRoles = data || [];
  }
  
  let automodConfig = null;
  if (supabase) {
    const { data } = await supabase
      .from('automod_config')
      .select('*')
      .eq('guild_id', guildId)
      .single();
    automodConfig = data;
  }
  
  return {
    guildInfo: {
      name: guild.name,
      icon: guild.iconURL(),
      ownerId: guild.ownerId,
      memberCount: guild.memberCount
    },
    roles,
    channels,
    categories,
    botConfig,
    levelRoles,
    automodConfig,
    backupVersion: '1.0'
  };
}

async function performRestore(guild, backupData, components, supabase) {
  const results = {
    roles: { created: 0, failed: 0, skipped: 0 },
    channels: { created: 0, failed: 0, skipped: 0 },
    botConfig: false
  };
  
  if (components === 'all' || components === 'roles') {
    const existingRoles = new Set(guild.roles.cache.map(r => r.name));
    
    for (const roleData of backupData.roles || []) {
      if (existingRoles.has(roleData.name)) {
        results.roles.skipped++;
        continue;
      }
      
      try {
        await guild.roles.create({
          name: roleData.name,
          color: roleData.color,
          hoist: roleData.hoist,
          permissions: BigInt(roleData.permissions),
          mentionable: roleData.mentionable,
          reason: 'Restored from backup'
        });
        results.roles.created++;
      } catch (e) {
        results.roles.failed++;
      }
    }
  }
  
  if (components === 'all' || components === 'channels') {
    const existingChannels = new Set(guild.channels.cache.map(c => c.name));
    
    for (const catData of backupData.categories || []) {
      if (existingChannels.has(catData.name)) continue;
      
      try {
        await guild.channels.create({
          name: catData.name,
          type: 4,
          reason: 'Restored from backup'
        });
      } catch (e) {
        console.error('Failed to create category:', e.message);
      }
    }
    
    for (const channelData of backupData.channels || []) {
      if (existingChannels.has(channelData.name)) {
        results.channels.skipped++;
        continue;
      }
      
      try {
        const parent = channelData.parentId 
          ? guild.channels.cache.find(c => c.name === (backupData.categories?.find(cat => cat.id === channelData.parentId)?.name))
          : null;
        
        await guild.channels.create({
          name: channelData.name,
          type: channelData.type,
          topic: channelData.topic,
          nsfw: channelData.nsfw,
          rateLimitPerUser: channelData.rateLimitPerUser,
          parent: parent?.id,
          reason: 'Restored from backup'
        });
        results.channels.created++;
      } catch (e) {
        results.channels.failed++;
      }
    }
  }
  
  if ((components === 'all' || components === 'bot_config') && supabase && backupData.botConfig) {
    try {
      await supabase.from('server_config').upsert({
        ...backupData.botConfig,
        guild_id: guild.id,
        updated_at: new Date().toISOString()
      });
      results.botConfig = true;
    } catch (e) {
      console.error('Failed to restore bot config:', e.message);
    }
  }
  
  return results;
}

function formatBytes(bytes) {
  if (!bytes || bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}

module.exports.createBackup = createBackup;
module.exports.performRestore = performRestore;
