import { Events, type Client, type PartialUser, type User } from 'discord.js';
import { SelfRoleModeSchema, t } from '@nexumi/shared';
import type { BotContext } from '../../types.js';
import { getGuildLocale } from '../../i18n.js';
import { logger } from '../../logger.js';
import {
  findPanelByMessageId,
  matchReactionEntry,
  parseRolesJson,
  SelfRoleError,
  toggleSelfRole
} from './service.js';

async function handleReactionToggle(
  context: BotContext,
  messageId: string,
  userId: string,
  emojiId: string | null,
  emojiName: string,
  add: boolean
): Promise<void> {
  const panel = await findPanelByMessageId(context, messageId);
  if (!panel || SelfRoleModeSchema.parse(panel.mode) !== 'REACTIONS') {
    return;
  }

  const { entries } = parseRolesJson(panel.roles);
  const entry = matchReactionEntry(entries, emojiId, emojiName);
  if (!entry) {
    return;
  }

  const guild = await context.client.guilds.fetch(panel.guildId).catch(() => null);
  if (!guild) {
    return;
  }

  const member = await guild.members.fetch(userId).catch(() => null);
  if (!member || member.user.bot) {
    return;
  }

  const behavior = panel.behavior;
  const hasRole = member.roles.cache.has(entry.roleId);

  if (add) {
    if (behavior === 'VERIFY' || behavior === 'TEMPORARY') {
      if (hasRole) {
        return;
      }
    } else if (behavior === 'NORMAL' && hasRole) {
      return;
    }
  } else {
    if (behavior === 'VERIFY') {
      return;
    }
    if (!hasRole) {
      return;
    }
  }

  try {
    await toggleSelfRole(context, panel, member, entry.roleId);
  } catch (error) {
    if (error instanceof SelfRoleError) {
      const locale = await getGuildLocale(context.prisma, panel.guildId);
      try {
        const user = await context.client.users.fetch(userId);
        await user.send(t(locale, `selfroles.error.${error.code}`));
      } catch {
        // User may have DMs disabled
      }
      return;
    }
    logger.error({ error, panelId: panel.id, userId }, 'Self-role reaction handler failed');
  }
}

export function registerSelfRoleEvents(client: Client, context: BotContext): void {
  client.on(Events.MessageReactionAdd, async (reaction, user: User | PartialUser) => {
    try {
      if (user.bot || !reaction.message.guildId) {
        return;
      }

      const message = reaction.message.partial
        ? await reaction.message.fetch().catch(() => null)
        : reaction.message;
      if (!message) {
        return;
      }

      await handleReactionToggle(
        context,
        message.id,
        user.id,
        reaction.emoji.id,
        reaction.emoji.name ?? '',
        true
      );
    } catch (error) {
      logger.error({ error }, 'Self-role reaction add failed');
    }
  });

  client.on(Events.MessageReactionRemove, async (reaction, user: User | PartialUser) => {
    try {
      if (user.bot || !reaction.message.guildId) {
        return;
      }

      const message = reaction.message.partial
        ? await reaction.message.fetch().catch(() => null)
        : reaction.message;
      if (!message) {
        return;
      }

      await handleReactionToggle(
        context,
        message.id,
        user.id,
        reaction.emoji.id,
        reaction.emoji.name ?? '',
        false
      );
    } catch (error) {
      logger.error({ error }, 'Self-role reaction remove failed');
    }
  });
}
