import type {
  ButtonInteraction,
  ModalSubmitInteraction,
  StringSelectMenuInteraction
} from 'discord.js';
import { t, tf } from '@nexumi/shared';
import type { BotContext } from '../../types.js';
import { getGuildLocale } from '../../i18n.js';
import {
  buildOpenModal,
  openTicketForCategory,
  parseFormFields,
  parseRateButton,
  rateTicket,
  TICKET_MODAL_PREFIX,
  TICKET_OPEN_PREFIX,
  TICKET_RATE_PREFIX,
  TICKET_SELECT_ID,
  TicketError
} from './service.js';

export function isTicketInteraction(customId: string): boolean {
  return (
    customId.startsWith(TICKET_OPEN_PREFIX) ||
    customId === TICKET_SELECT_ID ||
    customId.startsWith(TICKET_MODAL_PREFIX) ||
    customId.startsWith(TICKET_RATE_PREFIX)
  );
}

async function replyTicketError(
  interaction: ButtonInteraction | StringSelectMenuInteraction | ModalSubmitInteraction,
  locale: 'de' | 'en',
  code: string
): Promise<void> {
  const content = t(locale, `ticket.error.${code}`);
  if (interaction.replied || interaction.deferred) {
    await interaction.followUp({ content, ephemeral: true });
  } else {
    await interaction.reply({ content, ephemeral: true });
  }
}

export async function handleOpenTicketRequest(
  interaction: ButtonInteraction | StringSelectMenuInteraction,
  context: BotContext,
  categoryId: string
): Promise<void> {
  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 category = await context.prisma.ticketCategory.findUnique({ where: { id: categoryId } });
  if (!category || category.guildId !== interaction.guildId) {
    await interaction.reply({ content: t(locale, 'ticket.error.category_not_found'), ephemeral: true });
    return;
  }

  const fields = parseFormFields(category.formFields);
  if (fields.length > 0) {
    await interaction.showModal(buildOpenModal(category, locale));
    return;
  }

  try {
    const member = await interaction.guild.members.fetch(interaction.user.id);
    const ticket = await openTicketForCategory(
      context,
      interaction.guild,
      member,
      categoryId,
      interaction.channelId ?? undefined
    );
    const channelRef = ticket.channelId ?? ticket.threadId;
    await interaction.reply({
      content: tf(locale, 'ticket.created', { channel: `<#${channelRef}>` }),
      ephemeral: true
    });
  } catch (error) {
    if (error instanceof TicketError) {
      await replyTicketError(interaction, locale, error.code);
      return;
    }
    throw error;
  }
}

export async function handleTicketInteraction(
  interaction: ButtonInteraction | StringSelectMenuInteraction | ModalSubmitInteraction,
  context: BotContext
): Promise<void> {
  const locale = await getGuildLocale(context.prisma, interaction.guildId);

  if (interaction.isStringSelectMenu() && interaction.customId === TICKET_SELECT_ID) {
    const categoryId = interaction.values[0];
    if (!categoryId) {
      await interaction.reply({ content: t(locale, 'ticket.error.category_not_found'), ephemeral: true });
      return;
    }
    await handleOpenTicketRequest(interaction, context, categoryId);
    return;
  }

  if (interaction.isButton()) {
    if (interaction.customId.startsWith(TICKET_OPEN_PREFIX)) {
      const categoryId = interaction.customId.slice(TICKET_OPEN_PREFIX.length);
      await handleOpenTicketRequest(interaction, context, categoryId);
      return;
    }

    const parsedRate = parseRateButton(interaction.customId);
    if (parsedRate) {
      try {
        await rateTicket(context, parsedRate.ticketId, interaction.user.id, parsedRate.rating);
        await interaction.update({
          content: tf(locale, 'ticket.rated', { rating: parsedRate.rating }),
          components: []
        });
      } catch (error) {
        if (error instanceof TicketError) {
          await interaction.reply({
            content: t(locale, `ticket.error.${error.code}`),
            ephemeral: true
          });
          return;
        }
        throw error;
      }
      return;
    }
  }

  if (interaction.isModalSubmit() && interaction.customId.startsWith(TICKET_MODAL_PREFIX)) {
    if (!interaction.inGuild() || !interaction.guild) {
      await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true });
      return;
    }

    const categoryId = interaction.customId.slice(TICKET_MODAL_PREFIX.length);
    const category = await context.prisma.ticketCategory.findUnique({ where: { id: categoryId } });
    if (!category) {
      await interaction.reply({ content: t(locale, 'ticket.error.category_not_found'), ephemeral: true });
      return;
    }

    const fields = parseFormFields(category.formFields);
    const formAnswers: Record<string, string> = {};
    if (fields.length > 0) {
      for (const field of fields) {
        formAnswers[field.label] = interaction.fields.getTextInputValue(field.id);
      }
    } else {
      formAnswers[t(locale, 'ticket.modal.subject')] = interaction.fields.getTextInputValue('subject');
    }

    try {
      const member = await interaction.guild.members.fetch(interaction.user.id);
      const ticket = await openTicketForCategory(
        context,
        interaction.guild,
        member,
        categoryId,
        interaction.channelId ?? undefined,
        formAnswers,
        formAnswers[t(locale, 'ticket.modal.subject')] ?? category.name
      );
      const channelRef = ticket.channelId ?? ticket.threadId;
      await interaction.reply({
        content: tf(locale, 'ticket.created', { channel: `<#${channelRef}>` }),
        ephemeral: true
      });
    } catch (error) {
      if (error instanceof TicketError) {
        await replyTicketError(interaction, locale, error.code);
        return;
      }
      throw error;
    }
  }
}
