import type {
  ButtonInteraction,
  ChannelSelectMenuInteraction,
  MentionableSelectMenuInteraction,
  ModalSubmitInteraction,
  RoleSelectMenuInteraction,
  StringSelectMenuInteraction,
  UserSelectMenuInteraction
} from 'discord.js';
import { decodeComponentCustomId, t, type DashboardModuleId } from '@nexumi/shared';
import { env } from './env.js';
import { getGuildLocale } from './i18n.js';
import { ephemeral } from './interaction-reply.js';
import { isModuleEnabled, moduleForComponent } from './module-gates.js';
import { isMaintenanceMode } from './presence.js';
import type { BotContext } from './types.js';
import {
  handleModerationConfirmation,
  isModerationConfirmation
} from './modules/moderation/confirmations.js';
import { handleVerificationButton } from './modules/verification/handlers.js';
import { isVerificationButton } from './modules/verification/service.js';
import {
  handleBlackjackButton,
  isBlackjackButton
} from './modules/economy/blackjack-buttons.js';
import {
  handleEmbedModal,
  handlePollButton,
  isEmbedModal,
  isPollButton
} from './modules/utility/index.js';
import { handleFunButton, isFunButton } from './modules/fun/index.js';
import { handleGiveawayButton, isGiveawayButton } from './modules/giveaways/index.js';
import { handleTicketInteraction, isTicketInteraction } from './modules/tickets/index.js';
import {
  handleSelfRoleInteraction,
  isSelfRoleInteraction
} from './modules/selfroles/index.js';
import {
  handleSuggestionButton,
  isSuggestionButton
} from './modules/suggestions/index.js';
import {
  handleTempVoiceInteraction,
  isTempVoiceInteraction,
  isTempVoiceModal
} from './modules/tempvoice/index.js';
import { handleGuildBackupButton, isGuildBackupButton } from './modules/guildbackup/index.js';
import {
  handleComponentsV2Interaction,
  isComponentsV2Interaction
} from './modules/components-v2/index.js';

type AnyComponentInteraction =
  | ButtonInteraction
  | StringSelectMenuInteraction
  | UserSelectMenuInteraction
  | RoleSelectMenuInteraction
  | ChannelSelectMenuInteraction
  | MentionableSelectMenuInteraction
  | ModalSubmitInteraction;

type InteractionHandler = {
  match: (customId: string) => boolean;
  handle: (interaction: AnyComponentInteraction, context: BotContext) => Promise<void>;
};

function asButton(interaction: AnyComponentInteraction): ButtonInteraction {
  return interaction as ButtonInteraction;
}

function asModal(interaction: AnyComponentInteraction): ModalSubmitInteraction {
  return interaction as ModalSubmitInteraction;
}

const handlers: InteractionHandler[] = [
  {
    match: isModerationConfirmation,
    handle: (interaction, context) => handleModerationConfirmation(asButton(interaction), context)
  },
  {
    match: isVerificationButton,
    handle: (interaction, context) => handleVerificationButton(asButton(interaction), context)
  },
  {
    match: isBlackjackButton,
    handle: (interaction, context) => handleBlackjackButton(asButton(interaction), context)
  },
  {
    match: isPollButton,
    handle: (interaction, context) => handlePollButton(asButton(interaction), context)
  },
  {
    match: isFunButton,
    handle: (interaction, context) => handleFunButton(asButton(interaction), context)
  },
  {
    match: isGiveawayButton,
    handle: (interaction, context) => handleGiveawayButton(asButton(interaction), context)
  },
  {
    match: isTicketInteraction,
    handle: (interaction, context) =>
      handleTicketInteraction(
        interaction as Parameters<typeof handleTicketInteraction>[0],
        context
      )
  },
  {
    match: isSelfRoleInteraction,
    handle: (interaction, context) =>
      handleSelfRoleInteraction(
        interaction as Parameters<typeof handleSelfRoleInteraction>[0],
        context
      )
  },
  {
    match: isSuggestionButton,
    handle: (interaction, context) => handleSuggestionButton(asButton(interaction), context)
  },
  {
    match: (customId) => isTempVoiceInteraction(customId) || isTempVoiceModal(customId),
    handle: (interaction, context) =>
      handleTempVoiceInteraction(
        interaction as Parameters<typeof handleTempVoiceInteraction>[0],
        context
      )
  },
  {
    match: isGuildBackupButton,
    handle: (interaction, context) => handleGuildBackupButton(asButton(interaction), context)
  },
  {
    match: isEmbedModal,
    handle: (interaction, context) => handleEmbedModal(asModal(interaction), context)
  },
  {
    match: isComponentsV2Interaction,
    handle: (interaction, context) =>
      handleComponentsV2Interaction(
        interaction as Parameters<typeof handleComponentsV2Interaction>[0],
        context
      )
  }
];

function moduleForComponentsV2(customId: string): DashboardModuleId | null {
  const decoded = decodeComponentCustomId(customId);
  if (!decoded) {
    return null;
  }
  switch (decoded.source) {
    case 'w':
      return 'welcome';
    case 't':
      return 'tags';
    case 's':
      return 'scheduler';
    case 'm':
      return 'messages';
    default:
      return 'messages';
  }
}

export async function routeComponentInteraction(
  interaction: AnyComponentInteraction,
  context: BotContext
): Promise<boolean> {
  const customId = interaction.customId;
  const locale = await getGuildLocale(context.prisma, interaction.guildId);

  const maintenance = await isMaintenanceMode(context);
  const ownerIds = env.OWNER_USER_IDS ?? [];
  if (maintenance.enabled && !ownerIds.includes(interaction.user.id)) {
    if (!interaction.replied && !interaction.deferred) {
      await interaction.reply({
        content: maintenance.message?.trim() || t(locale, 'generic.maintenance'),
        ...ephemeral()
      });
    }
    return true;
  }

  let moduleId = moduleForComponent(customId);
  if (!moduleId && isComponentsV2Interaction(customId)) {
    moduleId = moduleForComponentsV2(customId);
  }

  if (moduleId && interaction.guildId) {
    const enabled = await isModuleEnabled(
      context.prisma,
      context.redis,
      interaction.guildId,
      moduleId
    );
    if (!enabled) {
      if (!interaction.replied && !interaction.deferred) {
        await interaction.reply({
          content: t(locale, 'generic.moduleDisabled'),
          ...ephemeral()
        });
      }
      return true;
    }
  }

  for (const handler of handlers) {
    if (handler.match(customId)) {
      await handler.handle(interaction, context);
      return true;
    }
  }
  return false;
}
