import { 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 { ticketCommandData } from './command-definitions.js';
import {
  addUserToTicket,
  assertTicketStaff,
  buildPanelComponents,
  buildPanelEmbed,
  claimTicket,
  closeTicket,
  createCategoryWithRole,
  findTicketByChannel,
  getGuildCategories,
  removeUserFromTicket,
  renameTicket,
  setTicketPriority,
  TicketError,
  upsertCategoryByName
} from './service.js';

async function ensureManageGuild(
  interaction: Parameters<SlashCommand['execute']>[0],
  locale: 'de' | 'en'
): Promise<boolean> {
  if (!interaction.inGuild()) {
    await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true });
    return false;
  }
  return requirePermission(interaction, PermissionFlagsBits.ManageGuild, locale);
}

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

    const sub = interaction.options.getSubcommand(true);

    if (sub === 'panel_create') {
      if (!(await ensureManageGuild(interaction, locale))) {
        return;
      }

      const name = interaction.options.getString('name', true);
      const description = interaction.options.getString('description');
      await upsertCategoryByName(context, interaction.guildId!, name, description);

      const categories = await getGuildCategories(context, interaction.guildId!);
      if (categories.length === 0) {
        await interaction.reply({ content: t(locale, 'ticket.error.no_categories'), ephemeral: true });
        return;
      }

      const channel = interaction.channel;
      if (!channel?.isTextBased() || channel.isDMBased()) {
        await interaction.reply({
          content: t(locale, 'ticket.error.invalid_channel'),
          ephemeral: true
        });
        return;
      }

      const embed = buildPanelEmbed(locale, name, description);
      const components = buildPanelComponents(categories);
      await channel.send({ embeds: [embed], components });
      await interaction.reply({ content: t(locale, 'ticket.panel.created'), ephemeral: true });
      return;
    }

    if (sub === 'category_create') {
      if (!(await ensureManageGuild(interaction, locale))) {
        return;
      }

      const name = interaction.options.getString('name', true);
      const role = interaction.options.getRole('support_role', true);
      const category = await createCategoryWithRole(
        context,
        interaction.guildId!,
        name,
        role.id
      );
      await interaction.reply({
        content: tf(locale, 'ticket.category.created', { name: category.name }),
        ephemeral: true
      });
      return;
    }

    const ticket = await findTicketByChannel(context.prisma, interaction.channelId!);
    if (!ticket) {
      await interaction.reply({ content: t(locale, 'ticket.error.not_in_ticket'), ephemeral: true });
      return;
    }

    const member = await interaction.guild!.members.fetch(interaction.user.id);

    try {
      if (sub === 'close') {
        const isStaff = await (async () => {
          try {
            await assertTicketStaff(member, ticket);
            return true;
          } catch {
            return false;
          }
        })();
        const isOpener = ticket.openerId === interaction.user.id;

        if (!isStaff && !isOpener) {
          await interaction.reply({ content: t(locale, 'ticket.error.not_staff'), ephemeral: true });
          return;
        }

        const reason = interaction.options.getString('reason') ?? undefined;
        await closeTicket(context, ticket, interaction.user.id, locale, reason);
        await interaction.reply({ content: t(locale, 'ticket.close.success'), ephemeral: true });
        return;
      }

      if (sub === 'claim') {
        await claimTicket(context, ticket, member, locale);
        await interaction.reply({ content: t(locale, 'ticket.claim.success'), ephemeral: true });
        return;
      }

      if (sub === 'add') {
        const user = interaction.options.getUser('user', true);
        const target = await interaction.guild!.members.fetch(user.id);
        await addUserToTicket(context, ticket, member, target, locale);
        await interaction.reply({
          content: tf(locale, 'ticket.add.success', { user: `<@${user.id}>` }),
          ephemeral: true
        });
        return;
      }

      if (sub === 'remove') {
        const user = interaction.options.getUser('user', true);
        const target = await interaction.guild!.members.fetch(user.id);
        await removeUserFromTicket(context, ticket, member, target, locale);
        await interaction.reply({
          content: tf(locale, 'ticket.remove.success', { user: `<@${user.id}>` }),
          ephemeral: true
        });
        return;
      }

      if (sub === 'rename') {
        const name = interaction.options.getString('name', true);
        await renameTicket(context, ticket, member, name, locale);
        await interaction.reply({
          content: tf(locale, 'ticket.rename.success', { name }),
          ephemeral: true
        });
        return;
      }

      if (sub === 'priority') {
        const level = interaction.options.getString('level', true);
        await setTicketPriority(context, ticket, member, level, locale);
        await interaction.reply({
          content: tf(locale, 'ticket.priority.success', {
            priority: t(locale, `ticket.priority.${level}`)
          }),
          ephemeral: true
        });
      }
    } catch (error) {
      if (error instanceof TicketError) {
        await interaction.reply({
          content: t(locale, `ticket.error.${error.code}`),
          ephemeral: true
        });
        return;
      }
      throw error;
    }
  }
};

export const ticketsCommands = [ticketCommand];
