import {
  REST,
  Routes,
  type ChatInputCommandInteraction,
  type MessageContextMenuCommandInteraction
} from 'discord.js';
import { t, tf, type Locale } from '@nexumi/shared';
import { env } from './env.js';
import { logger } from './logger.js';
import { getGuildLocale } from './i18n.js';
import { evaluateCommandGate, type CommandGateReason } from './command-gates.js';
import { isMaintenanceMode } from './presence.js';
import { moderationCommands } from './modules/moderation/commands.js';
import { automodCommands } from './modules/automod/commands.js';
import { welcomeCommands } from './modules/welcome/commands.js';
import { verificationCommands } from './modules/verification/commands.js';
import { levelingCommands } from './modules/leveling/commands.js';
import { economyCommands } from './modules/economy/commands.js';
import { utilityCommands, utilityContextMenus } from './modules/utility/index.js';
import { funCommands } from './modules/fun/index.js';
import { giveawayCommands } from './modules/giveaways/index.js';
import { ticketsCommands } from './modules/tickets/index.js';
import { selfrolesCommands } from './modules/selfroles/index.js';
import { tagsCommands } from './modules/tags/index.js';
import { starboardCommands } from './modules/starboard/index.js';
import { suggestionsCommands } from './modules/suggestions/index.js';
import { birthdayCommands } from './modules/birthdays/index.js';
import { tempVoiceCommands } from './modules/tempvoice/index.js';
import { statsCommands } from './modules/stats/index.js';
import { feedsCommands } from './modules/feeds/index.js';
import { scheduleCommands } from './modules/scheduler/index.js';
import { guildBackupCommands } from './modules/guildbackup/index.js';
import { coreCommands } from './modules/core/index.js';
import { gdprCommands } from './modules/gdpr/index.js';
import type { BotContext, SlashCommand } from './types.js';

const commands: SlashCommand[] = [
  ...coreCommands,
  ...gdprCommands,
  ...moderationCommands,
  ...automodCommands,
  ...welcomeCommands,
  ...verificationCommands,
  ...levelingCommands,
  ...economyCommands,
  ...utilityCommands,
  ...funCommands,
  ...giveawayCommands,
  ...ticketsCommands,
  ...selfrolesCommands,
  ...tagsCommands,
  ...starboardCommands,
  ...suggestionsCommands,
  ...birthdayCommands,
  ...tempVoiceCommands,
  ...statsCommands,
  ...feedsCommands,
  ...scheduleCommands,
  ...guildBackupCommands
];
const map = new Map(commands.map((c) => [c.data.name, c]));
const contextMenuMap = new Map(utilityContextMenus.map((c) => [c.data.name, c]));

export async function registerCommands() {
  const rest = new REST({ version: '10' }).setToken(env.BOT_TOKEN);
  const body = [
    ...commands.map((c) => c.data.toJSON()),
    ...utilityContextMenus.map((c) => c.data.toJSON())
  ];

  // Guild commands sync instantly; global can take up to ~1h.
  if (env.BOT_GUILD_ID) {
    await rest.put(Routes.applicationGuildCommands(env.BOT_CLIENT_ID, env.BOT_GUILD_ID), {
      body
    });
    logger.info(
      {
        scope: 'guild',
        guildId: env.BOT_GUILD_ID,
        count: commands.length,
        contextMenus: utilityContextMenus.length
      },
      'Registered guild application commands'
    );
    return;
  }

  await rest.put(Routes.applicationCommands(env.BOT_CLIENT_ID), { body });
  logger.info(
    {
      scope: 'global',
      count: commands.length,
      contextMenus: utilityContextMenus.length
    },
    'Registered global application commands'
  );
}

function gateMessage(locale: Locale, reason: CommandGateReason, retryAfterSeconds?: number): string {
  switch (reason) {
    case 'disabled':
      return t(locale, 'generic.commandDisabled');
    case 'channel_denied':
    case 'channel_not_allowed':
      return t(locale, 'generic.commandChannelBlocked');
    case 'role_denied':
    case 'role_not_allowed':
      return t(locale, 'generic.commandRoleBlocked');
    case 'cooldown':
      return tf(locale, 'generic.commandCooldown', {
        seconds: retryAfterSeconds ?? 1
      });
    default:
      return t(locale, 'generic.noPermission');
  }
}

export async function routeCommand(interaction: ChatInputCommandInteraction, context: BotContext) {
  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)) {
    await interaction.reply({
      content: maintenance.message?.trim() || t(locale, 'generic.maintenance'),
      ephemeral: true
    });
    return;
  }

  const command = map.get(interaction.commandName);
  if (!command) {
    await interaction.reply({ content: t(locale, 'generic.unknownCommand'), ephemeral: true });
    return;
  }

  const gate = await evaluateCommandGate(interaction, context);
  if (!gate.ok) {
    await interaction.reply({
      content: gateMessage(locale, gate.reason, gate.retryAfterSeconds),
      ephemeral: true
    });
    return;
  }

  await command.execute(interaction, context);
}

export async function routeContextMenu(
  interaction: MessageContextMenuCommandInteraction,
  context: BotContext
) {
  const command = contextMenuMap.get(interaction.commandName);
  const locale = await getGuildLocale(context.prisma, interaction.guildId);
  if (!command) {
    await interaction.reply({ content: t(locale, 'generic.unknownCommand'), ephemeral: true });
    return;
  }
  await command.execute(interaction, context);
}
