const { SlashCommandBuilder, ModalBuilder, TextInputStyle, TextInputBuilder, ActionRowBuilder, ChannelType, PermissionsBitField, ButtonBuilder, ButtonStyle, ComponentType } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Users, Team } = require('../functions/models.js');
const { applyUsername } = require('../functions/utils.js');
const { client } = require('../index.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('team')
    .setDescription('Team command')
    .addSubcommand(subcommand => subcommand
      .setName('create')
      .setDescription('Create a team'))
    .addSubcommand(subcommand => subcommand
      .setName('invite')
      .setDescription('Invite an user')
      .addUserOption(option => option
        .setName('user')
        .setDescription('The user to invite')
        .setRequired(true)))
    .addSubcommand(subcommand => subcommand
      .setName('leave')
      .setDescription('Leave your team')),

  async execute(interaction) {
    const user = await Users.findOne({ where: { id: interaction.user.id } });
    if (!user) return await interaction.reply({ embeds: [simpleEmbed('Error while getting user information')], ephemeral: true });

    if (interaction.options.getSubcommand() === 'create') {
      if (user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are already in a team')], ephemeral: true });

      const modal = new ModalBuilder()
        .setCustomId('teamCreate')
        .setTitle('Create team');

      const nameInput = new TextInputBuilder()
        .setCustomId('nameInput')
        .setLabel('Team name')
        .setMinLength(3)
        .setMaxLength(16)
        .setStyle(TextInputStyle.Short);

      const colorInput = new TextInputBuilder()
        .setCustomId('colorInput')
        .setLabel('Team color (hex)')
        .setStyle(TextInputStyle.Short)
        .setPlaceholder('#00ff00');

      const firstActionRow = new ActionRowBuilder().addComponents(nameInput);
      const secondActionRow = new ActionRowBuilder().addComponents(colorInput);

      modal.addComponents(firstActionRow, secondActionRow);

      await interaction.showModal(modal);

      try {
        const filter = (filterInteraction) => filterInteraction.customId === 'teamCreate';
        const modalInteraction = await interaction.awaitModalSubmit({ filter, time: 10 * 60 * 1000 });

        const teamName = modalInteraction.fields.getTextInputValue('nameInput');
        const teamColor = modalInteraction.fields.getTextInputValue('colorInput');

        if (!/^[a-zA-Z0-9]+$/.test(teamName)) return await modalInteraction.reply({ embeds: [simpleEmbed('Team name can only include alphanumeric characters')], ephemeral: true });
        if (!/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(teamColor)) return await modalInteraction.reply({ embeds: [simpleEmbed('Team color must be a valid hex code. [Color Picker](https://htmlcolorcodes.com/color-picker/)')], ephemeral: true });


        const guild = await client.guilds.fetch(process.env.GUILD_ID);
        const category = await guild.channels.fetch(process.env.TEAM_CATEGORY_ID);

        const textChannel = await guild.channels.create({
          name: teamName,
          type: ChannelType.GuildText,
          parent: category,
          permissionOverwrites: [
            {
              id: guild.id,
              deny: [PermissionsBitField.Flags.ViewChannel],
            },
            {
              id: interaction.member.id,
              allow: [PermissionsBitField.Flags.ViewChannel],
            },
          ],
        });

        const voiceChannel = await guild.channels.create({
          name: teamName,
          type: ChannelType.GuildVoice,
          parent: category,
          permissionOverwrites: [
            {
              id: guild.id,
              deny: [PermissionsBitField.Flags.ViewChannel],
            },
            {
              id: interaction.member.id,
              allow: [PermissionsBitField.Flags.ViewChannel],
            },
          ],
        });

        const team = await Team.create({
          name: teamName,
          color: teamColor,
          textChannelId: textChannel.id,
          voiceChannelId: voiceChannel.id,
        });

        await team.addMembers([ user ]);

        await applyUsername(user, interaction.member);

        await modalInteraction.reply({ embeds: [simpleEmbed(`Successfully created team **${teamName}**`)], ephemeral: true });
      } catch (error) {
        console.error(error);
      }
    } else if (interaction.options.getSubcommand() === 'leave') {
      if (!user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are not in a team')], ephemeral: true });

      const team = await user.getTeam();
      await team.removeMember(user);

      const guild = await client.guilds.fetch(process.env.GUILD_ID);

      const textChannel = await guild.channels.fetch(team.textChannelId);
      const voiceChannel = await guild.channels.fetch(team.voiceChannelId);


      if (await team.countMembers() <= 0) {
        await textChannel.delete();
        await voiceChannel.delete();

        await team.destroy();
      } else {
        await textChannel.permissionOverwrites.delete(interaction.member);
        await voiceChannel.permissionOverwrites.delete(interaction.member);
      }

      await applyUsername(user, interaction.member);

      await interaction.reply({ embeds: [simpleEmbed('Successfully left team')], ephemeral: true });
    } else if (interaction.options.getSubcommand() === 'invite') {
      if (!user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are not in a team')], ephemeral: true });

      const invitedUser = interaction.options.getUser('user');
      if (interaction.user.id === invitedUser.id) return await interaction.reply({ embeds: [simpleEmbed('You cannot invite yourself')], ephemeral: true });

      const invitedUserInstance = await Users.findOne({ where: { id: invitedUser.id } });
      if (invitedUserInstance.teamId) return await interaction.reply({ embeds: [simpleEmbed('The user you are trying already is in a team')], ephemeral: true });

      const team = await user.getTeam();

      const acceptButton = new ButtonBuilder()
        .setCustomId('accept')
        .setLabel('Accept')
        .setStyle(ButtonStyle.Success);

      const denyButton = new ButtonBuilder()
        .setCustomId('deny')
        .setLabel('Deny')
        .setStyle(ButtonStyle.Danger);

      const row = new ActionRowBuilder()
        .addComponents(acceptButton, denyButton);

      const inviteMessage = await invitedUser.send({
        embeds: [simpleEmbed(`**${user.rawUsername}** invited you to join team **${team.name}**`)],
        components: [row],
      });

      await interaction.reply({ embeds: [simpleEmbed(`Successfully invited ${invitedUser} to your team`)], ephemeral: true });

      const collector = inviteMessage.createMessageComponentCollector({ componentType: ComponentType.Button, time: 60 * 60 * 1000 });

      collector.on('collect', async i => {
        try {
          if (i.customId === 'accept') {
            await invitedUserInstance.reload();
            if (invitedUserInstance.teamId) return await i.message.edit({ embeds: [simpleEmbed('You are already in a team')], components: [] });

            await team.addMember(i.user.id);

            const guild = await client.guilds.fetch(process.env.GUILD_ID);
            const member = await guild.members.fetch(i.user.id);

            const textChannel = await guild.channels.fetch(team.textChannelId);
            const voiceChannel = await guild.channels.fetch(team.voiceChannelId);

            await textChannel.permissionOverwrites.edit(member, { ViewChannel: true });
            await voiceChannel.permissionOverwrites.edit(member, { ViewChannel: true });

            await applyUsername(invitedUserInstance, member);

            await i.message.edit({ embeds: [simpleEmbed(`Successfully joined team **${team.name}**`)], components: [] });
          } else if (i.customId === 'deny') {
            await i.message.edit({ embeds: [simpleEmbed(`Successfully denied the request to join team **${team.name}**`)], components: [] });
          }
        } catch (error) {
          console.error(error);
        }
      });

      collector.on('end', async () => {
        inviteMessage.edit({ embeds: [simpleEmbed('Confirmation not received within 1 hour, cancelling')], components: [] });
      });
    }
  },
};
