import { cartoes, contas, lancamentos } from "@/db/schema"; import { db } from "@/lib/db"; import { loadLogoOptions } from "@/lib/logo/options"; import { and, eq, ilike, isNull, not, or, sql } from "drizzle-orm"; export type CardData = { id: string; name: string; brand: string | null; status: string | null; closingDay: number; dueDay: number; note: string | null; logo: string | null; limit: number | null; limitInUse: number; limitAvailable: number | null; contaId: string; contaName: string; }; export type AccountSimple = { id: string; name: string; logo: string | null; }; export async function fetchCardsForUser(userId: string): Promise<{ cards: CardData[]; accounts: AccountSimple[]; logoOptions: LogoOption[]; }> { const [cardRows, accountRows, logoOptions, usageRows] = await Promise.all([ db.query.cartoes.findMany({ orderBy: (card: typeof cartoes.$inferSelect, { desc }: { desc: (field: unknown) => unknown }) => [desc(card.name)], where: and(eq(cartoes.userId, userId), not(ilike(cartoes.status, "inativo"))), with: { conta: { columns: { id: true, name: true, }, }, }, }), db.query.contas.findMany({ orderBy: (account: typeof contas.$inferSelect, { desc }: { desc: (field: unknown) => unknown }) => [desc(account.name)], where: eq(contas.userId, userId), columns: { id: true, name: true, logo: true, }, }), loadLogoOptions(), db .select({ cartaoId: lancamentos.cartaoId, total: sql`coalesce(sum(${lancamentos.amount}), 0)`, }) .from(lancamentos) .where( and( eq(lancamentos.userId, userId), or(isNull(lancamentos.isSettled), eq(lancamentos.isSettled, false)) ) ) .groupBy(lancamentos.cartaoId), ]); const usageMap = new Map(); usageRows.forEach((row: { cartaoId: string | null; total: number | null }) => { if (!row.cartaoId) return; usageMap.set(row.cartaoId, Number(row.total ?? 0)); }); const cards = cardRows.map((card) => ({ id: card.id, name: card.name, brand: card.brand, status: card.status, closingDay: card.closingDay, dueDay: card.dueDay, note: card.note, logo: card.logo, limit: card.limit ? Number(card.limit) : null, limitInUse: (() => { const total = usageMap.get(card.id) ?? 0; return total < 0 ? Math.abs(total) : 0; })(), limitAvailable: (() => { if (!card.limit) { return null; } const total = usageMap.get(card.id) ?? 0; const inUse = total < 0 ? Math.abs(total) : 0; return Math.max(Number(card.limit) - inUse, 0); })(), contaId: card.contaId, contaName: card.conta?.name ?? "Conta não encontrada", })); const accounts = accountRows.map((account) => ({ id: account.id, name: account.name, logo: account.logo, })); return { cards, accounts, logoOptions }; } export async function fetchInativosForUser(userId: string): Promise<{ cards: CardData[]; accounts: AccountSimple[]; logoOptions: LogoOption[]; }> { const [cardRows, accountRows, logoOptions, usageRows] = await Promise.all([ db.query.cartoes.findMany({ orderBy: (card: typeof cartoes.$inferSelect, { desc }: { desc: (field: unknown) => unknown }) => [desc(card.name)], where: and(eq(cartoes.userId, userId), ilike(cartoes.status, "inativo")), with: { conta: { columns: { id: true, name: true, }, }, }, }), db.query.contas.findMany({ orderBy: (account: typeof contas.$inferSelect, { desc }: { desc: (field: unknown) => unknown }) => [desc(account.name)], where: eq(contas.userId, userId), columns: { id: true, name: true, logo: true, }, }), loadLogoOptions(), db .select({ cartaoId: lancamentos.cartaoId, total: sql`coalesce(sum(${lancamentos.amount}), 0)`, }) .from(lancamentos) .where( and( eq(lancamentos.userId, userId), or(isNull(lancamentos.isSettled), eq(lancamentos.isSettled, false)) ) ) .groupBy(lancamentos.cartaoId), ]); const usageMap = new Map(); usageRows.forEach((row: { cartaoId: string | null; total: number | null }) => { if (!row.cartaoId) return; usageMap.set(row.cartaoId, Number(row.total ?? 0)); }); const cards = cardRows.map((card) => ({ id: card.id, name: card.name, brand: card.brand, status: card.status, closingDay: card.closingDay, dueDay: card.dueDay, note: card.note, logo: card.logo, limit: card.limit ? Number(card.limit) : null, limitInUse: (() => { const total = usageMap.get(card.id) ?? 0; return total < 0 ? Math.abs(total) : 0; })(), limitAvailable: (() => { if (!card.limit) { return null; } const total = usageMap.get(card.id) ?? 0; const inUse = total < 0 ? Math.abs(total) : 0; return Math.max(Number(card.limit) - inUse, 0); })(), contaId: card.contaId, contaName: card.conta?.name ?? "Conta não encontrada", })); const accounts = accountRows.map((account) => ({ id: account.id, name: account.name, logo: account.logo, })); return { cards, accounts, logoOptions }; }