const {
  PermissionFlagsBits,
  ApplicationCommandOptionType,
  ChannelType,
  EmbedBuilder,
  ActionRowBuilder,
  ButtonBuilder,
  ButtonStyle,
} = require('discord.js')

const roleMenus = require('../../model/roleMenus')
const brand = require('../../brand')

// Capped at 5 roles per menu — a single Discord action row holds at most 5
// buttons, and one row keeps this a single simple slash command instead of
// needing a multi-step builder/modal flow.
const MAX_ROLES = 5

// role1/label1 are declared inline in `data` (ahead of the optional
// `description` option, per Discord's required-before-optional rule) — this
// generates the rest, all optional.
function roleOptions(from, to) {
  const opts = []
  for (let i = from; i <= to; i++) {
    opts.push({ name: `role${i}`, description: `Role #${i}`, type: ApplicationCommandOptionType.Role, required: false })
    opts.push({ name: `label${i}`, description: `Button label for role #${i} (default: role name)`, type: ApplicationCommandOptionType.String, required: false })
  }
  return opts
}

module.exports = {
  data: {
    name: 'rolemenu',
    description: 'Post a button menu for self-assignable roles (up to 5).',
    default_member_permissions: PermissionFlagsBits.ManageGuild.toString(),
    // Discord requires all required options before any optional ones across
    // the whole array — role1 (required) must come before description
    // (optional), even though they read more naturally in the other order.
    options: [
      { name: 'channel', description: 'Channel to post the menu in', type: ApplicationCommandOptionType.Channel, channel_types: [ChannelType.GuildText], required: true },
      { name: 'title', description: 'Menu title', type: ApplicationCommandOptionType.String, required: true },
      { name: 'role1', description: 'Role #1', type: ApplicationCommandOptionType.Role, required: true },
      { name: 'description', description: 'Menu description', type: ApplicationCommandOptionType.String, required: false },
      { name: 'label1', description: 'Button label for role #1 (default: role name)', type: ApplicationCommandOptionType.String, required: false },
      ...roleOptions(2, MAX_ROLES),
    ],
  },
  async execute(interaction) {
    const channel = interaction.options.getChannel('channel', true)
    const title = interaction.options.getString('title', true)
    const description = interaction.options.getString('description') || undefined

    const entries = []
    for (let i = 1; i <= MAX_ROLES; i++) {
      const role = interaction.options.getRole(`role${i}`)
      if (!role) continue
      const label = interaction.options.getString(`label${i}`) || role.name
      entries.push({ roleId: role.id, label })
    }

    if (entries.length === 0) {
      await interaction.reply({ content: 'Provide at least one role (role1).', ephemeral: true })
      return
    }

    const embed = new EmbedBuilder().setTitle(title).setColor(brand.accentInt)
    if (description) embed.setDescription(description)

    const row = new ActionRowBuilder().addComponents(
      entries.map((e) =>
        new ButtonBuilder().setCustomId(`rolemenu:${e.roleId}`).setLabel(e.label).setStyle(ButtonStyle.Secondary),
      ),
    )

    const message = await channel.send({ embeds: [embed], components: [row] })
    await roleMenus.add({
      guildId: interaction.guildId,
      channelId: channel.id,
      messageId: message.id,
      mapping: entries,
      createdBy: interaction.user.id,
    })

    await interaction.reply({ content: `Role menu posted in ${channel}.`, ephemeral: true })
  },
}
