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 { ephemeral } from '../../interaction-reply.js';
import { ticketCommandData } from './command-definitions.js';
import {
  addUserToTicket,
  assertTicketStaff,
  claimTicket,
  closeTicket,
  createCategoryWithRole,
  findTicketByChannel,
  getGuildCategories,
  removeUserFromTicket,
  renameTicket,
  setTicketPriority,
  syncTicketPanel,
  TicketError,
  TicketPanelError,
  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() });
    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() });
      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()
        });
        return;
      }

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

      try {
        await syncTicketPanel(context, interaction.guildId!, {
          channelId: channel.id,
          title: name,
          description
        });
        await interaction.reply({ content: t(locale, 'ticket.panel.created'), ...ephemeral() });
      } catch (error) {
        if (error instanceof TicketPanelError) {
          const key =
            error.code === 'no_categories'
              ? 'ticket.error.no_categories'
              : error.code === 'not_configured'
                ? 'ticket.error.invalid_channel'
                : 'ticket.error.missing_permission';
          await interaction.reply({ content: t(locale, key), ...ephemeral() });
          return;
        }
        throw error;
      }
      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()
      });
      return;
    }

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

    const member = await interaction.guild!.members.fetch(interaction.user.id).catch(() => null);
    if (!member) {
      await interaction.reply({
        content: t(locale, 'ticket.error.member_not_found'),
        ...ephemeral()
      });
      return;
    }

    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()
          });
          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() });
        return;
      }

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

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

      if (sub === 'remove') {
        const user = interaction.options.getUser('user', true);
        const target = await interaction.guild!.members.fetch(user.id).catch(() => null);
        if (!target) {
          await interaction.reply({
            content: t(locale, 'ticket.error.member_not_found'),
            ...ephemeral()
          });
          return;
        }
        await removeUserFromTicket(context, ticket, member, target, locale);
        await interaction.reply({
          content: tf(locale, 'ticket.remove.success', { user: `<@${user.id}>` }),
          ...ephemeral()
        });
        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()
        });
        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()
        });
      }
    } catch (error) {
      if (error instanceof TicketError) {
        await interaction.reply({
          content: t(locale, `ticket.error.${error.code}`),
          ...ephemeral()
        });
        return;
      }
      throw error;
    }
  }
};

export const ticketsCommands = [ticketCommand];
