import { PermissionFlagsBits, type GuildMember } from 'discord.js';
import type { BotContext } from '../../types.js';
import { getWelcomeConfig, resolveWelcomePayload } from './service.js';
import { sendLeaveMessage, sendWelcomeMessage } from './renderer.js';
import { logger } from '../../logger.js';

async function applyAutoroles(member: GuildMember, roleIds: string[]): Promise<void> {
  const me = member.guild.members.me;
  if (!me?.permissions.has(PermissionFlagsBits.ManageRoles)) {
    return;
  }
  const assignable = roleIds.filter((roleId) => {
    const role = member.guild.roles.cache.get(roleId);
    return role && role.position < me.roles.highest.position;
  });
  if (assignable.length === 0) {
    return;
  }
  await member.roles.add(assignable).catch((error) => {
    logger.warn({ error, memberId: member.id }, 'Failed to assign autoroles');
  });
}

export async function handleMemberWelcome(context: BotContext, member: GuildMember): Promise<void> {
  const config = await getWelcomeConfig(context.prisma, member.guild.id);

  const roleIds = member.user.bot ? config.botAutoroleIds : config.userAutoroleIds;
  await applyAutoroles(member, roleIds);

  if (config.welcomeEnabled && config.welcomeChannelId) {
    const channel = await member.guild.channels.fetch(config.welcomeChannelId).catch(() => null);
    if (channel?.isTextBased() && !channel.isDMBased()) {
      await sendWelcomeMessage(
        channel,
        resolveWelcomePayload(config),
        member,
        member.guild
      );
    }
  }

  if (config.welcomeDmEnabled && config.welcomeDmContent && !member.user.bot) {
    await member
      .send({ content: config.welcomeDmContent.replace('{user}', `<@${member.id}>`) })
      .catch(() => undefined);
  }
}

export async function handleMemberLeave(context: BotContext, member: GuildMember): Promise<void> {
  const config = await getWelcomeConfig(context.prisma, member.guild.id);
  if (!config.leaveEnabled || !config.leaveChannelId) {
    return;
  }
  const channel = await member.guild.channels.fetch(config.leaveChannelId).catch(() => null);
  if (!channel?.isTextBased() || channel.isDMBased()) {
    return;
  }
  const content = config.leaveContent ?? '{user.tag} left {server}.';
  await sendLeaveMessage(channel, content, member, member.guild);
}

export function registerWelcomeEvents(context: BotContext): void {
  context.client.on('guildMemberAdd', async (member) => {
    await handleMemberWelcome(context, member);
    const { handleAntiRaidJoin } = await import('../automod/actions.js');
    await handleAntiRaidJoin(context, member);
  });

  context.client.on('guildMemberRemove', async (member) => {
    if (!member.guild) {
      return;
    }
    await handleMemberLeave(context, member as GuildMember);
  });
}
