import type {
  TicketCategoryDashboard,
  TicketCategoryDashboardCreate,
  TicketCategoryDashboardUpdate,
  TicketConfigDashboard,
  TicketConfigDashboardPatch
} from '@nexumi/shared';
import type { TicketCategory } from '@prisma/client';
import { prisma } from '../prisma';

async function ensureTicketConfig(guildId: string) {
  await prisma.guild.upsert({ where: { id: guildId }, update: {}, create: { id: guildId } });
  return prisma.ticketConfig.upsert({ where: { guildId }, update: {}, create: { guildId } });
}

function toConfigDashboard(config: Awaited<ReturnType<typeof ensureTicketConfig>>): TicketConfigDashboard {
  return {
    enabled: config.enabled,
    mode: config.mode as TicketConfigDashboard['mode'],
    categoryId: config.categoryId ?? '',
    logChannelId: config.logChannelId ?? '',
    transcriptDm: config.transcriptDm,
    inactivityHours: config.inactivityHours,
    ratingEnabled: config.ratingEnabled
  };
}

export async function getTicketConfigDashboard(guildId: string): Promise<TicketConfigDashboard> {
  const config = await ensureTicketConfig(guildId);
  return toConfigDashboard(config);
}

export async function updateTicketConfigDashboard(
  guildId: string,
  patch: TicketConfigDashboardPatch
): Promise<TicketConfigDashboard> {
  await ensureTicketConfig(guildId);

  const { categoryId, logChannelId, ...rest } = patch;
  const updated = await prisma.ticketConfig.update({
    where: { guildId },
    data: {
      ...rest,
      ...(categoryId !== undefined ? { categoryId: categoryId === '' ? null : categoryId } : {}),
      ...(logChannelId !== undefined ? { logChannelId: logChannelId === '' ? null : logChannelId } : {})
    }
  });
  return toConfigDashboard(updated);
}

function toCategoryDashboard(category: TicketCategory): TicketCategoryDashboard {
  return {
    id: category.id,
    name: category.name,
    description: category.description,
    emoji: category.emoji,
    supportRoleIds: category.supportRoleIds
  };
}

export async function listTicketCategories(guildId: string): Promise<TicketCategoryDashboard[]> {
  const categories = await prisma.ticketCategory.findMany({
    where: { guildId },
    orderBy: { createdAt: 'asc' }
  });
  return categories.map(toCategoryDashboard);
}

export class TicketCategoryConflictError extends Error {
  constructor() {
    super('A ticket category with this name already exists');
  }
}

export async function createTicketCategory(
  guildId: string,
  input: TicketCategoryDashboardCreate
): Promise<TicketCategoryDashboard> {
  await prisma.guild.upsert({ where: { id: guildId }, update: {}, create: { id: guildId } });
  try {
    const category = await prisma.ticketCategory.create({
      data: {
        guildId,
        name: input.name,
        description: input.description ?? null,
        emoji: input.emoji ?? null,
        supportRoleIds: input.supportRoleIds
      }
    });
    return toCategoryDashboard(category);
  } catch (error) {
    if (error && typeof error === 'object' && 'code' in error && error.code === 'P2002') {
      throw new TicketCategoryConflictError();
    }
    throw error;
  }
}

export async function updateTicketCategory(
  guildId: string,
  categoryId: string,
  patch: TicketCategoryDashboardUpdate
): Promise<TicketCategoryDashboard | null> {
  const existing = await prisma.ticketCategory.findFirst({ where: { id: categoryId, guildId } });
  if (!existing) {
    return null;
  }

  try {
    const updated = await prisma.ticketCategory.update({
      where: { id: categoryId },
      data: {
        ...(patch.name !== undefined ? { name: patch.name } : {}),
        ...(patch.description !== undefined ? { description: patch.description } : {}),
        ...(patch.emoji !== undefined ? { emoji: patch.emoji } : {}),
        ...(patch.supportRoleIds !== undefined ? { supportRoleIds: patch.supportRoleIds } : {})
      }
    });
    return toCategoryDashboard(updated);
  } catch (error) {
    if (error && typeof error === 'object' && 'code' in error && error.code === 'P2002') {
      throw new TicketCategoryConflictError();
    }
    throw error;
  }
}

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