import type { DB } from './db' import type { GmailDeps, SendResult } from './gmail' import { sendReminderEmail } from './gmail' import { getClient } from './repos-clients' import { getClientModule } from './repos-modules' import { getDocument } from './repos-documents' import { getAmc } from './repos-amc' import { getReminder, setReminderStatus } from './repos-reminders' import { reminderEmail, type ReminderContext } from './reminder-templates' import { documentHtml } from './templates' /** Turn a queued/failed reminder into an actual email — used by the manual-queue * Send button and by the scheduler's auto path. Reuses gmail.sendReminderEmail. */ export interface SendReminderDeps { gmail: GmailDeps renderPdf: (html: string) => Promise company: () => Record now?: () => string } export async function sendReminder( db: DB, deps: SendReminderDeps, reminderId: string, userId: string, ): Promise { const reminder = getReminder(db, reminderId) if (reminder === null) throw new Error('Reminder not found') if (reminder.ruleKind === 'follow_up' || reminder.ruleKind === 'email_bounced') { throw new Error(`A ${reminder.ruleKind} reminder is an internal item, not a sendable email`) } const client = getClient(db, reminder.clientId) if (client === null) throw new Error('Client not found') const company = deps.company() const companyName = company['company.name'] ?? '' // Build the per-rule context. const ctx: ReminderContext = { clientName: client.name, companyName } let attachment: { filename: string; data: Buffer } | undefined let documentId: string | undefined if (reminder.docId !== null) { const doc = getDocument(db, reminder.docId) if (doc === null) throw new Error('Reminder document not found') documentId = doc.id ctx.docNo = doc.docNo ?? undefined ctx.amountPaise = doc.payablePaise ctx.period = reminder.duePeriod const pdf = await deps.renderPdf(documentHtml(doc, client, company)) attachment = { filename: `${(doc.docNo ?? 'draft').replaceAll('/', '-')}.pdf`, data: pdf } } else if (reminder.ruleKind === 'renewal_due') { const cm = getClientModule(db, reminder.subjectId) if (cm !== null && cm.nextRenewal !== null) ctx.dueDate = cm.nextRenewal } else if (reminder.ruleKind === 'amc_expiring') { const amc = getAmc(db, reminder.subjectId) if (amc !== null) { ctx.coverage = amc.coverage; ctx.dueDate = amc.periodTo } } const to = client.contacts.find((c) => c.email !== undefined && c.email !== '')?.email if (to === undefined) throw new Error('No recipient: add a contact email to the client') const mail = reminderEmail(reminder.ruleKind, ctx) const out = await sendReminderEmail(db, deps.gmail, { to, subject: mail.subject, bodyText: mail.bodyText, ...(attachment !== undefined ? { attachment } : {}), ...(documentId !== undefined ? { documentId } : {}), }) const now = deps.now?.() ?? new Date().toISOString() if (out.ok) setReminderStatus(db, userId, reminderId, 'sent', { sentAt: now, error: null }) else setReminderStatus(db, userId, reminderId, 'failed', { error: out.error }) return out }