import { AttachmentBuilder, EmbedBuilder, PermissionFlagsBits } from 'discord.js';
import { t, tf } from '@nexumi/shared';
import type { SlashCommand } from '../../types.js';
import { getGuildLocale } from '../../i18n.js';
import { requirePermission } from '../../permissions.js';
import {
  addXp,
  formatLeaderboardLine,
  getConfig,
  getLeaderboard,
  getOrCreateMemberLevel,
  getRankPosition,
  memberProgress,
  removeXp,
  resetXp
} from './service.js';
import { renderRankCard } from './rank-card.js';
import {
  leaderboardCommandData,
  rankCommandData,
  xpCommandData
} from './command-definitions.js';

const rankCommand: SlashCommand = {
  data: rankCommandData,
  async execute(interaction, context) {
    const locale = await getGuildLocale(context.prisma, interaction.guildId);
    if (!interaction.inGuild() || !interaction.guild) {
      await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true });
      return;
    }

    const targetUser = interaction.options.getUser('user') ?? interaction.user;
    const member = await interaction.guild.members.fetch(targetUser.id).catch(() => null);
    if (!member) {
      await interaction.reply({ content: t(locale, 'leveling.user.notFound'), ephemeral: true });
      return;
    }

    const config = await getConfig(context.prisma, interaction.guild.id);
    const memberLevel = await getOrCreateMemberLevel(context.prisma, interaction.guild.id, member.id);
    const rank = await getRankPosition(context.prisma, interaction.guild.id, member.id);
    const progress = memberProgress(memberLevel);

    const buffer = await renderRankCard({
      displayName: member.displayName,
      avatarUrl: member.user.displayAvatarURL({ extension: 'png', size: 256 }),
      level: progress.level,
      rank,
      intoLevel: progress.intoLevel,
      needed: progress.needed,
      totalXp: memberLevel.xp,
      accentColor: config.cardAccentColor,
      backgroundColor: config.cardBackgroundColor
    });

    const attachment = new AttachmentBuilder(buffer, { name: 'rank.png' });
    await interaction.reply({ files: [attachment] });
  }
};

const leaderboardCommand: SlashCommand = {
  data: leaderboardCommandData,
  async execute(interaction, context) {
    const locale = await getGuildLocale(context.prisma, interaction.guildId);
    if (!interaction.inGuild() || !interaction.guild) {
      await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true });
      return;
    }

    const entries = await getLeaderboard(context.prisma, interaction.guild.id, 10);
    if (entries.length === 0) {
      await interaction.reply({ content: t(locale, 'leveling.leaderboard.empty'), ephemeral: true });
      return;
    }

    const lines = await Promise.all(
      entries.map(async (entry, index) => {
        const user = await context.client.users.fetch(entry.userId).catch(() => null);
        const label = user ? `<@${entry.userId}>` : entry.userId;
        return formatLeaderboardLine(locale, index + 1, label, entry.level, entry.xp);
      })
    );

    const embed = new EmbedBuilder()
      .setTitle(t(locale, 'leveling.leaderboard.title'))
      .setDescription(lines.join('\n'))
      .setFooter({ text: tf(locale, 'leveling.leaderboard.footer', { count: entries.length }) })
      .setColor(0x6366f1);

    await interaction.reply({ embeds: [embed] });
  }
};

const xpCommand: SlashCommand = {
  data: xpCommandData,
  async execute(interaction, context) {
    const locale = await getGuildLocale(context.prisma, interaction.guildId);
    if (!interaction.inGuild() || !interaction.guild) {
      await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true });
      return;
    }
    if (!(await requirePermission(interaction, PermissionFlagsBits.ManageGuild, locale))) {
      return;
    }

    const sub = interaction.options.getSubcommand();
    const user = interaction.options.getUser('user', true);
    const member = await interaction.guild.members.fetch(user.id).catch(() => null);
    if (!member) {
      await interaction.reply({ content: t(locale, 'leveling.user.notFound'), ephemeral: true });
      return;
    }

    const channelId = interaction.channelId ?? undefined;

    if (sub === 'give') {
      const amount = interaction.options.getInteger('amount', true);
      const result = await addXp(context, interaction.guild, member, amount, {
        channelId,
        force: true
      });
      const level = result?.newLevel ?? (await getOrCreateMemberLevel(context.prisma, interaction.guild.id, member.id)).level;
      await interaction.reply({
        content: tf(locale, 'leveling.xp.give.success', {
          amount,
          user: `<@${member.id}>`,
          level
        }),
        ephemeral: true
      });
      return;
    }

    if (sub === 'remove') {
      const amount = interaction.options.getInteger('amount', true);
      const result = await removeXp(context, interaction.guild, member, amount, channelId);
      const level =
        result?.newLevel ??
        (await getOrCreateMemberLevel(context.prisma, interaction.guild.id, member.id)).level;
      await interaction.reply({
        content: tf(locale, 'leveling.xp.remove.success', {
          amount,
          user: `<@${member.id}>`,
          level
        }),
        ephemeral: true
      });
      return;
    }

    await resetXp(context, interaction.guild, member, channelId);
    await interaction.reply({
      content: tf(locale, 'leveling.xp.reset.success', { user: `<@${member.id}>` }),
      ephemeral: true
    });
  }
};

export const levelingCommands: SlashCommand[] = [rankCommand, leaderboardCommand, xpCommand];
