import {
  DashboardMessageSendResultSchema,
  MessageComponentsV2Schema,
  type DashboardMessageSend,
  type DashboardMessageSendResult
} from '@nexumi/shared';
import { Prisma } from '@prisma/client';
import { prisma } from '../prisma';
import { addJobAndAwait, getMessagesQueue, getMessagesQueueEvents } from '../queues';

export class MessageSendTimeoutError extends Error {
  constructor() {
    super('The bot did not confirm the message in time. It may still have been sent — check the channel shortly.');
  }
}

/**
 * Sends a dashboard message via the bot's `messages` BullMQ queue
 * (`dashboardMessageSend` job). For Components V2, a binding row is created
 * first so interaction custom IDs can reference a stable ref id.
 */
export async function sendDashboardMessageFromWebui(
  guildId: string,
  createdById: string,
  input: DashboardMessageSend
): Promise<DashboardMessageSendResult> {
  await prisma.guild.upsert({ where: { id: guildId }, update: {}, create: { id: guildId } });

  let bindingId: string | null = null;
  if (input.mode === 'COMPONENTS_V2') {
    const components = MessageComponentsV2Schema.parse(input.components);
    const binding = await prisma.componentMessageBinding.create({
      data: {
        guildId,
        channelId: input.channelId,
        payload: components as Prisma.InputJsonValue,
        createdById
      }
    });
    bindingId = binding.id;
  }

  const { confirmed, result } = await addJobAndAwait<{
    bindingId: string | null;
    messageId: string | null;
    channelId: string;
  }>(
    getMessagesQueue(),
    getMessagesQueueEvents(),
    'dashboardMessageSend',
    {
      guildId,
      channelId: input.channelId,
      createdById,
      mode: input.mode,
      embed: input.embed ?? null,
      components: input.components ?? null,
      bindingId
    },
    { removeOnComplete: true, removeOnFail: 25 }
  );

  if (!confirmed || !result) {
    throw new MessageSendTimeoutError();
  }

  return DashboardMessageSendResultSchema.parse({
    bindingId: result.bindingId ?? bindingId,
    messageId: result.messageId,
    channelId: result.channelId,
    confirmed: true
  });
}
