import { usePrisma } from "../utils/prisma"; // ─── Gruppen-Chat ───────────────────────────────────────────────────────────── export async function getChatMessages(limit = 100) { const db = usePrisma(); return db.chatMessage.findMany({ where: { roomId: null }, orderBy: { createdAt: "asc" }, take: limit, select: { id: true, content: true, createdAt: true, userId: true }, }); } export async function createChatMessage(userId: string, content: string) { const db = usePrisma(); return db.chatMessage.create({ data: { userId, content, roomId: null }, select: { id: true, content: true, createdAt: true, userId: true }, }); } // ─── Direktnachrichten ─────────────────────────────────────────────────────── export async function sendDirectMessage( senderId: string, receiverId: string, content: string, opts?: { replyToId?: string; attachmentUrl?: string; attachmentType?: string; attachmentName?: string; }, ) { const db = usePrisma(); const msg = await db.directMessage.create({ data: { senderId, receiverId, content, replyToId: opts?.replyToId || null, attachmentUrl: opts?.attachmentUrl || null, attachmentType: opts?.attachmentType || null, attachmentName: opts?.attachmentName || null, }, select: { id: true, content: true, createdAt: true, replyToId: true, attachmentUrl: true, attachmentType: true, attachmentName: true, likesCount: true, replyTo: { select: { id: true, senderId: true, content: true }, }, }, }); // Push-Notification (fire-and-forget — blockt Response nicht) void (async () => { const { sendChatPush, getDisplayName, truncatePreview } = await import( "../services/push" ); const senderName = await getDisplayName(senderId); await sendChatPush({ receiverId, senderName, preview: truncatePreview(content || (opts?.attachmentUrl ? "📎 Anhang" : "")), data: { type: "dm", targetId: senderId, messageId: msg.id }, }); })(); return msg; } export async function getDmHistory( userId: string, partnerId: string, page = 1, limit = 50, ) { const db = usePrisma(); const offset = (page - 1) * limit; return db.directMessage.findMany({ where: { OR: [ { senderId: userId, receiverId: partnerId }, { senderId: partnerId, receiverId: userId }, ], }, orderBy: { createdAt: "desc" }, skip: offset, take: limit, select: { id: true, senderId: true, receiverId: true, content: true, createdAt: true, readAt: true, replyToId: true, attachmentUrl: true, attachmentType: true, attachmentName: true, likesCount: true, deletedAt: true, reactions: { select: { userId: true, emoji: true }, }, replyTo: { select: { id: true, senderId: true, content: true }, }, }, }); } /** * Toggle einer Emoji-Reaktion auf eine DM (WhatsApp-Verhalten): * - kein Eintrag → Reaktion anlegen * - gleiches Emoji → Reaktion entfernen (toggle off) * - anderes Emoji → Reaktion ersetzen * Eine Reaktion pro User pro Message (PK user+message). */ export async function toggleDmReaction( userId: string, messageId: string, emoji: string, ) { const db = usePrisma(); const existing = await db.directMessageReaction.findUnique({ where: { userId_messageId: { userId, messageId } }, }); if (existing) { if (existing.emoji === emoji) { await db.directMessageReaction.delete({ where: { userId_messageId: { userId, messageId } }, }); return { emoji: null as string | null }; } const updated = await db.directMessageReaction.update({ where: { userId_messageId: { userId, messageId } }, data: { emoji }, }); return { emoji: updated.emoji }; } const created = await db.directMessageReaction.create({ data: { userId, messageId, emoji }, }); return { emoji: created.emoji }; } /** * Soft-Delete einer DM (Tombstone). Nur eigene Nachrichten löschbar. * @returns true wenn gelöscht, false wenn nicht erlaubt/nicht gefunden. */ export async function softDeleteDmMessage(userId: string, messageId: string) { const db = usePrisma(); const res = await db.directMessage.updateMany({ where: { id: messageId, senderId: userId, deletedAt: null }, data: { deletedAt: new Date() }, }); return res.count > 0; } export async function markDmsAsRead(senderId: string, receiverId: string) { const db = usePrisma(); return db.directMessage.updateMany({ where: { senderId, receiverId, readAt: null }, data: { readAt: new Date() }, }); } export async function getDmConversations(userId: string) { const db = usePrisma(); // Alle DMs als Sender oder Empfänger, neueste zuerst return db.directMessage.findMany({ where: { OR: [{ senderId: userId }, { receiverId: userId }], }, orderBy: { createdAt: "desc" }, take: 500, select: { id: true, senderId: true, receiverId: true, content: true, createdAt: true, readAt: true, }, }); } export async function countUnreadDms(receiverId: string) { const db = usePrisma(); const rows = await db.directMessage.findMany({ where: { receiverId, readAt: null }, select: { senderId: true }, }); const byPartner: Record = {}; for (const r of rows) { byPartner[r.senderId] = (byPartner[r.senderId] ?? 0) + 1; } return byPartner; }