import "server-only";
import { prisma } from "@/lib/prisma";
import type { NotificationType } from "@prisma/client";

type CreateArgs = {
  userId: string;
  type?: NotificationType;
  title: string;
  body?: string;
  link?: string;
};

/** Erstellt eine Benachrichtigung für einen Nutzer. */
export async function createNotification(args: CreateArgs) {
  return prisma.notification.create({
    data: {
      userId: args.userId,
      type: args.type ?? "GENERIC",
      title: args.title,
      body: args.body,
      link: args.link,
    },
  });
}

/** Mehrere Nutzer auf einmal benachrichtigen. */
export async function createNotifications(
  userIds: string[],
  data: Omit<CreateArgs, "userId">,
) {
  if (userIds.length === 0) return;
  await prisma.notification.createMany({
    data: userIds.map((userId) => ({
      userId,
      type: data.type ?? "GENERIC",
      title: data.title,
      body: data.body,
      link: data.link,
    })),
  });
}

/**
 * Benachrichtigung je Nutzer für ein Ziel (`link`) zusammenfassen: existiert
 * bereits eine ungelesene Meldung zum selben Link, wird sie aktualisiert statt
 * eine neue anzulegen. Verhindert, dass ein Chatverlauf die Glocke flutet.
 */
export async function upsertLinkNotification(
  userIds: string[],
  data: Omit<CreateArgs, "userId"> & { link: string },
) {
  if (userIds.length === 0) return;

  const type = data.type ?? "GENERIC";
  const title = data.title.slice(0, 200);
  const body = data.body?.slice(0, 500);

  const existing = await prisma.notification.findMany({
    where: { userId: { in: userIds }, link: data.link, type, readAt: null },
    select: { id: true, userId: true },
  });

  const updatedUserIds = new Set(existing.map((n) => n.userId));
  const toCreate = userIds.filter((id) => !updatedUserIds.has(id));

  if (existing.length > 0) {
    await prisma.notification.updateMany({
      where: { id: { in: existing.map((n) => n.id) } },
      data: { title, body, createdAt: new Date() },
    });
  }
  if (toCreate.length > 0) {
    await prisma.notification.createMany({
      data: toCreate.map((userId) => ({ userId, type, title, body, link: data.link })),
    });
  }
}

/** Meldungen zu einem Ziel als gelesen markieren (z. B. Kanal geöffnet). */
export async function markNotificationsReadByLink(userId: string, link: string) {
  await prisma.notification.updateMany({
    where: { userId, link, readAt: null },
    data: { readAt: new Date() },
  });
}

export async function getNotifications(userId: string, take = 15) {
  const [items, unread] = await Promise.all([
    prisma.notification.findMany({
      where: { userId },
      orderBy: { createdAt: "desc" },
      take,
    }),
    prisma.notification.count({ where: { userId, readAt: null } }),
  ]);
  return { items, unread };
}

export async function markAllNotificationsRead(userId: string) {
  await prisma.notification.updateMany({
    where: { userId, readAt: null },
    data: { readAt: new Date() },
  });
}
