import type { BotContext } from '../../types.js';
import { logger } from '../../logger.js';
import {
  awardVoiceXpForSession,
  handleTextXpMessage,
  voiceKey
} from './service.js';

async function handleVoiceJoin(context: BotContext, guildId: string, userId: string): Promise<void> {
  await context.redis.set(voiceKey(guildId, userId), String(Date.now()));
}

async function handleVoiceLeave(
  context: BotContext,
  guildId: string,
  userId: string,
  channelId: string
): Promise<void> {
  const key = voiceKey(guildId, userId);
  const joinedAt = await context.redis.get(key);
  await context.redis.del(key);
  if (!joinedAt) {
    return;
  }

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

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

  await awardVoiceXpForSession(context, guild, member, Number(joinedAt), channelId);
}

export function registerLevelingEvents(context: BotContext): void {
  context.client.on('messageCreate', async (message) => {
    try {
      if (!message.guild || message.author.bot || !message.member) {
        return;
      }
      await handleTextXpMessage(context, message.member, message.channel.id);
    } catch (error) {
      logger.error({ error, messageId: message.id }, 'Leveling message handler failed');
    }
  });

  context.client.on('voiceStateUpdate', async (oldState, newState) => {
    try {
      const guildId = newState.guild.id;
      const userId = newState.id;
      const oldChannelId = oldState.channelId;
      const newChannelId = newState.channelId;

      if (oldChannelId && oldChannelId !== newChannelId) {
        await handleVoiceLeave(context, guildId, userId, oldChannelId);
      }

      if (newChannelId && newChannelId !== oldChannelId) {
        await handleVoiceJoin(context, guildId, userId);
      }
    } catch (error) {
      logger.error({ error, userId: newState.id }, 'Leveling voice handler failed');
    }
  });
}
