import { GuildBackupPayloadSchema, type GuildBackupDashboard } from '@nexumi/shared';
import type { GuildBackup } from '@prisma/client';
import { buildGuildBackupPayloadViaRest } from '../guild-backup';
import { prisma } from '../prisma';
import { assertPremiumLimit, PremiumLimitError } from '../premium';
import { getGuildBackupQueue, guildBackupQueueName } from '../queues';

export class BackupPremiumError extends Error {
  constructor(public readonly code: 'premium_limit' | 'premium_feature') {
    super(code);
  }
}

async function ensureGuild(guildId: string): Promise<void> {
  await prisma.guild.upsert({ where: { id: guildId }, update: {}, create: { id: guildId } });
}

function toDashboard(backup: GuildBackup): GuildBackupDashboard {
  const parsed = GuildBackupPayloadSchema.safeParse(backup.payload);
  return {
    id: backup.id,
    name: backup.name,
    createdById: backup.createdById,
    createdAt: backup.createdAt.toISOString(),
    roleCount: parsed.success ? parsed.data.roles.length : 0,
    channelCount: parsed.success ? parsed.data.channels.length : 0
  };
}

export async function listGuildBackupsDashboard(guildId: string): Promise<GuildBackupDashboard[]> {
  const backups = await prisma.guildBackup.findMany({
    where: { guildId },
    orderBy: { createdAt: 'desc' },
    take: 15
  });
  return backups.map(toDashboard);
}

export async function getGuildBackupRecord(guildId: string, backupId: string): Promise<GuildBackup | null> {
  return prisma.guildBackup.findFirst({ where: { id: backupId, guildId } });
}

export async function createGuildBackupDashboard(
  guildId: string,
  name: string,
  createdById: string
): Promise<GuildBackupDashboard> {
  await ensureGuild(guildId);
  const currentCount = await prisma.guildBackup.count({ where: { guildId } });
  try {
    await assertPremiumLimit(prisma, guildId, 'backups', currentCount);
  } catch (error) {
    if (error instanceof PremiumLimitError) {
      throw new BackupPremiumError(error.code === 'feature_disabled' ? 'premium_feature' : 'premium_limit');
    }
    throw error;
  }
  const payload = await buildGuildBackupPayloadViaRest(guildId);
  const backup = await prisma.guildBackup.create({
    data: { guildId, name, createdById, payload }
  });
  return toDashboard(backup);
}

export async function deleteGuildBackupDashboard(guildId: string, backupId: string): Promise<boolean> {
  const result = await prisma.guildBackup.deleteMany({ where: { id: backupId, guildId } });
  return result.count > 0;
}

/**
 * Enqueues the same `restoreGuildBackup` BullMQ job the bot's `/backup
 * restore` command uses, so the actual restore (creating roles/channels via
 * discord.js) always runs on the bot process where the guild cache lives.
 */
export async function enqueueGuildBackupRestore(
  backupId: string,
  guildId: string,
  requestedById: string
): Promise<void> {
  await getGuildBackupQueue().add(
    'restoreGuildBackup',
    { backupId, guildId, requestedById },
    {
      jobId: `guild-backup-restore-${backupId}`,
      removeOnComplete: true,
      removeOnFail: 25
    }
  );
}

export { guildBackupQueueName };
