import type { Message, PartialMessage } from 'discord.js';
import type { BotContext } from '../../types.js';
import { logger } from '../../logger.js';
import {
  processStarboardReaction,
  processStarboardSourceDelete,
  processStarboardSourceUpdate
} from './service.js';

export function registerStarboardEvents(context: BotContext): void {
  const handleReaction = async (
    reaction: Parameters<typeof processStarboardReaction>[1]
  ): Promise<void> => {
    try {
      await processStarboardReaction(context, reaction);
    } catch (error) {
      logger.warn({ error }, 'Starboard reaction handler failed');
    }
  };

  context.client.on('messageReactionAdd', async (_reaction, user) => {
    if (user.bot) {
      return;
    }
    await handleReaction(_reaction);
  });

  context.client.on('messageReactionRemove', async (_reaction, user) => {
    if (user.bot) {
      return;
    }
    await handleReaction(_reaction);
  });

  context.client.on('messageReactionRemoveAll', async (message) => {
    try {
      if (message.partial) {
        await message.fetch().catch(() => null);
      }
      if (!message.guild || !('author' in message) || !message.author) {
        return;
      }
      await processStarboardSourceUpdate(context, message as Message | PartialMessage);
    } catch (error) {
      logger.warn({ error }, 'Starboard remove-all handler failed');
    }
  });

  context.client.on('messageReactionRemoveEmoji', async (reaction) => {
    await handleReaction(reaction);
  });

  context.client.on('messageDelete', async (message) => {
    try {
      await processStarboardSourceDelete(context, message);
    } catch (error) {
      logger.warn({ error }, 'Starboard source-delete handler failed');
    }
  });

  context.client.on('messageDeleteBulk', async (messages) => {
    for (const message of messages.values()) {
      try {
        await processStarboardSourceDelete(context, message);
      } catch (error) {
        logger.warn({ error }, 'Starboard bulk-delete handler failed');
      }
    }
  });

  context.client.on('messageUpdate', async (_oldMessage, newMessage) => {
    try {
      await processStarboardSourceUpdate(context, newMessage);
    } catch (error) {
      logger.warn({ error }, 'Starboard source-update handler failed');
    }
  });
}
