import { TextChannel, type ButtonInteraction } from 'discord.js';
import { type Locale, t, tf } from '@nexumi/shared';
import type { BotContext } from '../../types.js';
import { assertBannableForConfirm } from '../../hierarchy.js';
import { createCase, scheduleTempBanExpire } from './service.js';
import { tryParseDuration } from './duration.js';

type BanPayload = {
  userId: string;
  reason: string;
  duration: string | null;
};

type PurgePayload = {
  channelId: string;
  amount: number;
  targetUserId: string | null;
  botsOnly: boolean;
  linksOnly: boolean;
  attachmentsOnly: boolean;
  regex: string | null;
};

type CaseDeletePayload = {
  caseNumber: number;
};

export async function executeBan(
  interaction: ButtonInteraction,
  context: BotContext,
  locale: Locale,
  payload: BanPayload
): Promise<void> {
  const guild = interaction.guild;
  if (!guild) {
    await interaction.update({ content: t(locale, 'generic.guildOnly'), components: [] });
    return;
  }

  if (!(await assertBannableForConfirm(interaction, locale, payload.userId))) {
    return;
  }

  let durationMs: number | null = null;
  if (payload.duration) {
    durationMs = tryParseDuration(payload.duration);
    if (durationMs === null || durationMs <= 0) {
      await interaction.update({
        content: t(locale, 'moderation.duration.invalid'),
        components: []
      });
      return;
    }
  }

  await interaction.deferUpdate();

  await guild.members.ban(payload.userId, { reason: payload.reason });
  const modCase = await createCase(context, {
    guildId: guild.id,
    targetUserId: payload.userId,
    moderatorId: interaction.user.id,
    action: 'BAN',
    reason: payload.reason,
    channelId: interaction.channelId ?? undefined,
    source: 'button_confirmation',
    metadata: {
      confirmed: true,
      duration: payload.duration,
      durationMs
    }
  });

  if (durationMs !== null) {
    await scheduleTempBanExpire(guild.id, payload.userId, durationMs, payload.reason);
  }

  await interaction.editReply({
    content: tf(locale, 'moderation.success.caseWithReason', {
      caseNumber: modCase.caseNumber,
      reason: payload.reason
    }),
    components: []
  });
}

export async function executePurge(
  interaction: ButtonInteraction,
  context: BotContext,
  locale: Locale,
  payload: PurgePayload
): Promise<void> {
  const guild = interaction.guild;
  if (!guild) {
    await interaction.update({ content: t(locale, 'generic.guildOnly'), components: [] });
    return;
  }

  await interaction.deferUpdate();

  const channel = await guild.channels.fetch(payload.channelId);
  let deletedCount = 0;
  const regex = payload.regex ? new RegExp(payload.regex, 'i') : null;

  if (channel instanceof TextChannel) {
    const fetched = await channel.messages.fetch({ limit: 100 });
    const filtered = fetched.filter((message) => {
      if (payload.targetUserId && message.author.id !== payload.targetUserId) return false;
      if (payload.botsOnly && !message.author.bot) return false;
      if (payload.linksOnly && !/(https?:\/\/|discord\.gg\/)/i.test(message.content)) return false;
      if (payload.attachmentsOnly && message.attachments.size === 0) return false;
      if (regex && !regex.test(message.content)) return false;
      return true;
    });
    const toDelete = filtered.first(payload.amount);
    const deleted = await channel.bulkDelete(toDelete, true);
    deletedCount = deleted.size;
  }

  const modCase = await createCase(context, {
    guildId: guild.id,
    targetUserId: interaction.user.id,
    moderatorId: interaction.user.id,
    action: 'PURGE',
    reason: `Deleted ${deletedCount} messages`,
    channelId: payload.channelId,
    source: 'button_confirmation',
    metadata: {
      confirmed: true,
      purge: {
        requestedAmount: payload.amount,
        deletedCount,
        filters: {
          targetUserId: payload.targetUserId,
          botsOnly: payload.botsOnly,
          linksOnly: payload.linksOnly,
          attachmentsOnly: payload.attachmentsOnly,
          regex: payload.regex
        }
      }
    }
  });

  await interaction.editReply({
    content: tf(locale, 'moderation.purge.done', {
      deletedCount,
      caseNumber: modCase.caseNumber
    }),
    components: []
  });
}

export async function executeCaseDelete(
  interaction: ButtonInteraction,
  context: BotContext,
  locale: Locale,
  payload: CaseDeletePayload
): Promise<void> {
  const guildId = interaction.guildId;
  if (!guildId) {
    await interaction.update({ content: t(locale, 'generic.guildOnly'), components: [] });
    return;
  }

  const existing = await context.prisma.case.findUnique({
    where: { guildId_caseNumber: { guildId, caseNumber: payload.caseNumber } }
  });

  if (!existing || existing.deletedAt) {
    await interaction.update({
      content: t(locale, 'moderation.case.notFound'),
      components: []
    });
    return;
  }

  await context.prisma.case.update({
    where: { guildId_caseNumber: { guildId, caseNumber: payload.caseNumber } },
    data: { deletedAt: new Date() }
  });

  const modCase = await createCase(context, {
    guildId,
    targetUserId: existing.targetUserId,
    moderatorId: interaction.user.id,
    action: 'CASE_DELETE',
    reason: `Soft-deleted case #${payload.caseNumber}`,
    channelId: interaction.channelId ?? undefined,
    source: 'button_confirmation',
    metadata: {
      confirmed: true,
      deletedCaseId: existing.id,
      deletedCaseNumber: payload.caseNumber
    }
  });

  await interaction.update({
    content: tf(locale, 'moderation.success.case', { caseNumber: modCase.caseNumber }),
    components: []
  });
}
