import type { Prisma, PrismaClient } from "@prisma/client"; type BudgetSessionAccessor = | Pick | Pick; function normalizeAvailableCents(value: number): bigint { if (!Number.isFinite(value)) return 0n; return BigInt(Math.max(0, Math.trunc(value))); } export async function getLatestBudgetSession( db: BudgetSessionAccessor, userId: string ) { return db.budgetSession.findFirst({ where: { userId }, orderBy: { periodStart: "desc" }, }); } export async function ensureBudgetSession( db: BudgetSessionAccessor, userId: string, fallbackAvailableCents = 0, now = new Date() ) { const existing = await getLatestBudgetSession(db, userId); if (existing) return existing; const start = new Date( Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1, 0, 0, 0, 0) ); const end = new Date( Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1, 0, 0, 0, 0) ); const normalizedAvailable = normalizeAvailableCents(fallbackAvailableCents); return db.budgetSession.create({ data: { userId, periodStart: start, periodEnd: end, totalBudgetCents: normalizedAvailable, allocatedCents: 0n, fundedCents: 0n, availableCents: normalizedAvailable, }, }); } export async function ensureBudgetSessionAvailableSynced( db: BudgetSessionAccessor, userId: string, availableCents: number ) { const normalizedAvailable = normalizeAvailableCents(availableCents); const session = await ensureBudgetSession( db, userId, Number(normalizedAvailable) ); if ((session.availableCents ?? 0n) === normalizedAvailable) return session; return db.budgetSession.update({ where: { id: session.id }, data: { availableCents: normalizedAvailable }, }); }