import { TRPCError } from "@trpc/server";
import { db } from "@minmon/db";
import { domain, note, server, service } from "@minmon/db";
import { and, eq } from "drizzle-orm";

export function createEntityId() {
  return crypto.randomUUID();
}

export function stripUndefined<T extends Record<string, unknown>>(values: T) {
  return Object.fromEntries(
    Object.entries(values).filter(([, value]) => value !== undefined),
  ) as Partial<T>;
}

export function notFound(message: string): never {
  throw new TRPCError({
    code: "NOT_FOUND",
    message,
  });
}

export function badRequest(message: string): never {
  throw new TRPCError({
    code: "BAD_REQUEST",
    message,
  });
}

export async function requireServer(serverId: string) {
  const [item] = await db.select().from(server).where(eq(server.id, serverId)).limit(1);
  if (!item) {
    notFound("Server not found");
  }
  return item;
}

export async function requireService(serviceId: string) {
  const [item] = await db.select().from(service).where(eq(service.id, serviceId)).limit(1);
  if (!item) {
    notFound("Service not found");
  }
  return item;
}

export async function requireDomain(domainId: string) {
  const [item] = await db.select().from(domain).where(eq(domain.id, domainId)).limit(1);
  if (!item) {
    notFound("Domain not found");
  }
  return item;
}

export async function requireNote(noteId: string) {
  const [item] = await db.select().from(note).where(eq(note.id, noteId)).limit(1);
  if (!item) {
    notFound("Note not found");
  }
  return item;
}

export async function requireServiceWithServer(serviceId: string) {
  const item = await requireService(serviceId);
  const parentServer = await requireServer(item.serverId);
  return { service: item, server: parentServer };
}

export async function requireDomainWithRelations(domainId: string) {
  const item = await requireDomain(domainId);
  const parentService = await requireService(item.serviceId);
  const parentServer = await requireServer(parentService.serverId);
  return { domain: item, service: parentService, server: parentServer };
}

export async function ensureServiceBelongsToServer(serviceId: string, serverId: string) {
  const [item] = await db
    .select()
    .from(service)
    .where(and(eq(service.id, serviceId), eq(service.serverId, serverId)))
    .limit(1);

  if (!item) {
    badRequest("Service does not belong to the selected server");
  }

  return item;
}
