import {
  type ChatInputCommandInteraction,
  type GuildMember,
  type Interaction
} from 'discord.js';
import type { Locale } from '@nexumi/shared';
import { t } from '@nexumi/shared';

export type HierarchyAction = 'ban' | 'kick' | 'timeout' | 'nick';

export type HierarchyOk = { ok: true; member: GuildMember | null };
export type HierarchyDenied = { ok: false };

/**
 * Validates that the moderator and bot can act on the target member.
 * Replies ephemerally on denial. For bans, `member` may be null if the user
 * already left the guild (ban-by-id is still allowed).
 */
export async function assertModerableMember(
  interaction: ChatInputCommandInteraction,
  targetUserId: string,
  locale: Locale,
  action: HierarchyAction
): Promise<HierarchyOk | HierarchyDenied> {
  const guild = interaction.guild;
  if (!guild) {
    await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true });
    return { ok: false };
  }

  if (targetUserId === interaction.user.id) {
    await interaction.reply({ content: t(locale, 'moderation.hierarchy.self'), ephemeral: true });
    return { ok: false };
  }

  if (targetUserId === guild.ownerId) {
    await interaction.reply({ content: t(locale, 'moderation.hierarchy.owner'), ephemeral: true });
    return { ok: false };
  }

  let member: GuildMember | null = null;
  try {
    member = await guild.members.fetch(targetUserId);
  } catch {
    if (action === 'ban') {
      return { ok: true, member: null };
    }
    await interaction.reply({ content: t(locale, 'moderation.hierarchy.notMember'), ephemeral: true });
    return { ok: false };
  }

  const moderator =
    interaction.member && 'roles' in interaction.member
      ? (interaction.member as GuildMember)
      : await guild.members.fetch(interaction.user.id);

  if (guild.ownerId !== moderator.id) {
    if (member.roles.highest.position >= moderator.roles.highest.position) {
      await interaction.reply({
        content: t(locale, 'moderation.hierarchy.moderator'),
        ephemeral: true
      });
      return { ok: false };
    }
  }

  const botOk =
    action === 'ban'
      ? member.bannable
      : action === 'kick'
        ? member.kickable
        : action === 'timeout'
          ? member.moderatable
          : member.manageable;

  if (!botOk) {
    await interaction.reply({
      content: t(locale, 'moderation.hierarchy.bot'),
      ephemeral: true
    });
    return { ok: false };
  }

  return { ok: true, member };
}

async function replyHierarchyForButton(interaction: Interaction, locale: Locale, key: string): Promise<void> {
  if (!interaction.isRepliable()) {
    return;
  }
  const content = t(locale, key);
  if (interaction.isButton()) {
    await interaction.update({ content, components: [] });
    return;
  }
  if (interaction.replied || interaction.deferred) {
    await interaction.followUp({ content, ephemeral: true });
  } else {
    await interaction.reply({ content, ephemeral: true });
  }
}

export async function assertBannableForConfirm(
  interaction: Interaction,
  locale: Locale,
  targetUserId: string
): Promise<boolean> {
  const guild = interaction.guild;
  if (!guild) {
    await replyHierarchyForButton(interaction, locale, 'generic.guildOnly');
    return false;
  }
  if (targetUserId === interaction.user.id) {
    await replyHierarchyForButton(interaction, locale, 'moderation.hierarchy.self');
    return false;
  }
  if (targetUserId === guild.ownerId) {
    await replyHierarchyForButton(interaction, locale, 'moderation.hierarchy.owner');
    return false;
  }

  try {
    const member = await guild.members.fetch(targetUserId);
    if (!member.bannable) {
      await replyHierarchyForButton(interaction, locale, 'moderation.hierarchy.bot');
      return false;
    }
    const moderator = await guild.members.fetch(interaction.user.id);
    if (
      guild.ownerId !== moderator.id &&
      member.roles.highest.position >= moderator.roles.highest.position
    ) {
      await replyHierarchyForButton(interaction, locale, 'moderation.hierarchy.moderator');
      return false;
    }
  } catch {
    // Target left the guild — ban by id is still fine.
  }

  return true;
}
