import { type TextChannel } from 'discord.js';
import { t, tf } from '@nexumi/shared';
import type { BotContext } from '../../types.js';
import { ensureGuild } from '../../guild.js';
import { safeRemoveBullJob } from '../../lib/safe-remove-job.js';
import { reminderQueue } from '../../queues.js';
import { parseWhen, UtilityError } from './service.js';

export async function createReminder(
  context: BotContext,
  params: {
    guildId: string | null;
    userId: string;
    channelId: string;
    content: string;
    whenInput: string;
    recurringCron?: string | null;
  }
): Promise<string> {
  if (params.guildId) {
    await ensureGuild(context.prisma, params.guildId);
  }

  const remindAt = parseWhen(params.whenInput);
  const delayMs = remindAt.getTime() - Date.now();

  const reminder = await context.prisma.reminder.create({
    data: {
      guildId: params.guildId,
      userId: params.userId,
      channelId: params.channelId,
      content: params.content,
      remindAt,
      recurringCron: params.recurringCron ?? null
    }
  });

  const jobOptions: {
    jobId: string;
    removeOnComplete: boolean;
    removeOnFail: number;
    delay?: number;
    repeat?: { pattern: string };
  } = {
    jobId: `reminder-${reminder.id}`,
    removeOnComplete: true,
    removeOnFail: 50
  };

  if (params.recurringCron) {
    jobOptions.repeat = { pattern: params.recurringCron };
  } else {
    jobOptions.delay = Math.max(0, delayMs);
  }

  const job = await reminderQueue.add(
    'reminderSend',
    { reminderId: reminder.id },
    jobOptions
  );

  await context.prisma.reminder.update({
    where: { id: reminder.id },
    data: { jobId: String(job.id) }
  });

  return reminder.id;
}

export async function listReminders(
  context: BotContext,
  userId: string,
  locale: 'de' | 'en'
): Promise<string> {
  const reminders = await context.prisma.reminder.findMany({
    where: { userId },
    orderBy: { remindAt: 'asc' },
    take: 20
  });

  if (reminders.length === 0) {
    return t(locale, 'utility.reminders.none');
  }

  return reminders
    .map((r) =>
      tf(locale, 'utility.reminders.line', {
        id: r.id.slice(0, 8),
        time: `<t:${Math.floor(r.remindAt.getTime() / 1000)}:R>`,
        content: r.content.slice(0, 80)
      })
    )
    .join('\n');
}

export async function deleteReminder(
  context: BotContext,
  userId: string,
  reminderIdPrefix: string
): Promise<boolean> {
  const reminders = await context.prisma.reminder.findMany({
    where: { userId }
  });
  const match = reminders.find((r) => r.id.startsWith(reminderIdPrefix));
  if (!match) {
    return false;
  }

  if (match.jobId) {
    const job = await reminderQueue.getJob(match.jobId);
    await safeRemoveBullJob(job, { label: 'reminder', jobId: match.jobId });
  }

  await context.prisma.reminder.delete({ where: { id: match.id } });
  return true;
}

export async function sendReminder(context: BotContext, reminderId: string): Promise<void> {
  const reminder = await context.prisma.reminder.findUnique({ where: { id: reminderId } });
  if (!reminder) {
    return;
  }

  try {
    const channel = (await context.client.channels.fetch(reminder.channelId)) as TextChannel;
    await channel.send({
      content: `<@${reminder.userId}> ${reminder.content}`
    });
  } catch {
    throw new UtilityError('reminder_channel_unavailable');
  }

  if (!reminder.recurringCron) {
    await context.prisma.reminder.delete({ where: { id: reminderId } });
  } else {
    await context.prisma.reminder.update({
      where: { id: reminderId },
      data: { remindAt: new Date(Date.now() + 60_000) }
    });
  }
}
