import { getPrisma } from '@/lib/prisma' import { ExpenseFormValues, GroupFormValues } from '@/lib/schemas' import { Expense } from '@prisma/client' import { nanoid } from 'nanoid' export function randomId() { return nanoid() } export async function createGroup(groupFormValues: GroupFormValues) { const prisma = await getPrisma() return prisma.group.create({ data: { id: randomId(), name: groupFormValues.name, currency: groupFormValues.currency, participants: { createMany: { data: groupFormValues.participants.map(({ name }) => ({ id: randomId(), name, })), }, }, }, include: { participants: true }, }) } export async function createExpense( expenseFormValues: ExpenseFormValues, groupId: string, ): Promise { const group = await getGroup(groupId) if (!group) throw new Error(`Invalid group ID: ${groupId}`) for (const participant of [ expenseFormValues.paidBy, ...expenseFormValues.paidFor.map((p) => p.participant), ]) { if (!group.participants.some((p) => p.id === participant)) throw new Error(`Invalid participant ID: ${participant}`) } const prisma = await getPrisma() return prisma.expense.create({ data: { id: randomId(), groupId, amount: expenseFormValues.amount, title: expenseFormValues.title, paidById: expenseFormValues.paidBy, splitMode: expenseFormValues.splitMode, paidFor: { createMany: { data: expenseFormValues.paidFor.map((paidFor) => ({ participantId: paidFor.participant, shares: paidFor.shares, })), }, }, isReimbursement: expenseFormValues.isReimbursement, }, }) } export async function deleteExpense(expenseId: string) { const prisma = await getPrisma() await prisma.expense.delete({ where: { id: expenseId }, include: { paidFor: true, paidBy: true }, }) } export async function getGroupExpensesParticipants(groupId: string) { const expenses = await getGroupExpenses(groupId) return Array.from( new Set( expenses.flatMap((e) => [ e.paidById, ...e.paidFor.map((pf) => pf.participantId), ]), ), ) } export async function getGroups(groupIds: string[]) { const prisma = await getPrisma() return ( await prisma.group.findMany({ where: { id: { in: groupIds } }, include: { _count: { select: { participants: true } } }, }) ).map((group) => ({ ...group, createdAt: group.createdAt.toISOString(), })) } export async function updateExpense( groupId: string, expenseId: string, expenseFormValues: ExpenseFormValues, ) { const group = await getGroup(groupId) if (!group) throw new Error(`Invalid group ID: ${groupId}`) const existingExpense = await getExpense(groupId, expenseId) if (!existingExpense) throw new Error(`Invalid expense ID: ${expenseId}`) for (const participant of [ expenseFormValues.paidBy, ...expenseFormValues.paidFor.map((p) => p.participant), ]) { if (!group.participants.some((p) => p.id === participant)) throw new Error(`Invalid participant ID: ${participant}`) } const prisma = await getPrisma() return prisma.expense.update({ where: { id: expenseId }, data: { amount: expenseFormValues.amount, title: expenseFormValues.title, paidById: expenseFormValues.paidBy, splitMode: expenseFormValues.splitMode, paidFor: { create: expenseFormValues.paidFor .filter( (p) => !existingExpense.paidFor.some( (pp) => pp.participantId === p.participant, ), ) .map((paidFor) => ({ participantId: paidFor.participant, shares: paidFor.shares, })), update: expenseFormValues.paidFor.map((paidFor) => ({ where: { expenseId_participantId: { expenseId, participantId: paidFor.participant, }, }, data: { shares: paidFor.shares, }, })), deleteMany: existingExpense.paidFor.filter( (paidFor) => !expenseFormValues.paidFor.some( (pf) => pf.participant === paidFor.participantId, ), ), }, isReimbursement: expenseFormValues.isReimbursement, }, }) } export async function updateGroup( groupId: string, groupFormValues: GroupFormValues, ) { const existingGroup = await getGroup(groupId) if (!existingGroup) throw new Error('Invalid group ID') const prisma = await getPrisma() return prisma.group.update({ where: { id: groupId }, data: { name: groupFormValues.name, currency: groupFormValues.currency, participants: { deleteMany: existingGroup.participants.filter( (p) => !groupFormValues.participants.some((p2) => p2.id === p.id), ), updateMany: groupFormValues.participants .filter((participant) => participant.id !== undefined) .map((participant) => ({ where: { id: participant.id }, data: { name: participant.name, }, })), createMany: { data: groupFormValues.participants .filter((participant) => participant.id === undefined) .map((participant) => ({ id: randomId(), name: participant.name, })), }, }, }, }) } export async function getGroup(groupId: string) { const prisma = await getPrisma() return prisma.group.findUnique({ where: { id: groupId }, include: { participants: true }, }) } export async function getGroupExpenses(groupId: string) { const prisma = await getPrisma() return prisma.expense.findMany({ where: { groupId }, include: { paidFor: { include: { participant: true } }, paidBy: true }, orderBy: { createdAt: 'desc' }, }) } export async function getExpense(groupId: string, expenseId: string) { const prisma = await getPrisma() return prisma.expense.findUnique({ where: { id: expenseId }, include: { paidBy: true, paidFor: true }, }) }