import type { SplitType } from "@/lib/store/expense-store"; import type { z } from "zod"; import { expenseSplitSchema } from "../validations/expense"; import type { ExpenseSplit } from "@/server/db/schema"; const debtSchema = expenseSplitSchema.pick({ owedFromId: true, owedToId: true, amount: true, }); export type Debt = z.infer; export type Payment = { userId: string; amount: number; }; export function calculateSplits(args: { amount: number; users: Array; splitType: SplitType; payments?: Array; }): Record { const result: Record = {}; const { splitType = "Equal", amount, users, payments } = args; switch (splitType) { case "Equal": var splits: Record = {}; users.forEach((userId) => { splits[userId] = `${amount / users.length}€`; }); return splits; // case "Percentage": // if (!customDepts) { // throw new Error("Splits must be provided for percentage type."); // } // participants.forEach((userId) => { // if (customDepts[userId] !== undefined) { // const percentage = customDepts[userId] / 100; // const amountSplit = amount * percentage; // result[userId] = `${amountSplit.toFixed(2)}%`; // Add "%" for percentage // } else { // throw new Error(`No percentage split defined for user ID: ${userId}`); // } // }); // break; // case "Fixed": // if (!customDepts) { // throw new Error("Splits must be provided for fixed type."); // } // participants.forEach((userId) => { // if (customDepts[userId] !== undefined) { // result[userId] = `${customDepts[userId].toFixed(2)}`; // Format to 2 decimal places // } else { // throw new Error(`No fixed amount defined for user ID: ${userId}`); // } // }); // break; default: return {}; // throw new Error("Invalid split type."); } return result; } export function calculateDepts( total: number, users: string[], payments: Array ): Array { console.log("Payments: ", payments); const share = total / users.length; const balances: Record = {}; // Initialize balances users.forEach((userId) => { const paid = payments.find((p) => p.userId === userId)?.amount || 0; balances[userId] = paid - share; }); // Separate creditors and debtors const creditors = Object.entries(balances) .filter(([_, balance]) => balance > 0) .map(([userId, balance]) => ({ userId, balance })); const debtors = Object.entries(balances) .filter(([_, balance]) => balance < 0) .map(([userId, balance]) => ({ userId, balance: -balance })); console.log("debtors: ", debtors); console.log("creditors: ", creditors); const debts: Debt[] = []; for (const debtor of debtors) { let amountToPay = debtor.balance; for (const creditor of creditors) { if (amountToPay === 0) break; if (creditor.balance === 0) continue; const payment = Math.min(amountToPay, creditor.balance); debts.push({ owedToId: debtor.userId, owedFromId: creditor.userId, amount: parseFloat(payment.toFixed(2)), // for rounding safety }); amountToPay -= payment; creditor.balance -= payment; } } return debts; } export const calculateTotalValue: ( userId: string, splits: Array ) => { owed: number; owes: number; } = (userId, splits) => { let owed = 0; let owes = 0; splits.forEach((split) => { if (split.owedToId === userId) { owes += Number(split.amount); // You are the debitor } else if (split.owedFromId === userId) { owed += Number(split.amount); // You are the creditor } }); return { owed, owes }; };