import type { DecisionKind, LetterTemplate, OutgoingLetter } from "./types"; export type StatusKind = "hired" | "withdrawn" | "other"; /** * "Hired", "hired " and "HIRED" are the same decision. "Offer accepted" is a * different one and is never read as Hired. With normalisation off (tests only) * the comparison is exact. */ export function statusKind(raw: string, normalized = true): StatusKind { const s = normalized ? raw.trim().replace(/\s+/g, " ").toLowerCase() : raw; if (s === (normalized ? "hired" : "Hired")) return "hired"; if (s === (normalized ? "withdrawn" : "Withdrawn")) return "withdrawn"; return "other"; } export function normalizeAddress(a: string): string { return a.trim().toLowerCase(); } // Deliberately plain: one @, a dot in the domain, no spaces. The mail service is the final judge. export function looksLikeAddress(a: string): boolean { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(a.trim()); } export function decisionKind(raw: string): DecisionKind | null { const s = raw.trim().toLowerCase(); if (s === "send again") return "send-again"; if (s === "confirm sent") return "confirm-sent"; if (s === "approve new address") return "approve-new-address"; return null; } const MONTHS = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; const DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; /** "2026-10-05" -> "Monday, October 5". Computed in UTC so page and Apps Script agree. */ export function longDate(iso: string): string { const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso); if (!m) return iso; const d = new Date(Date.UTC(+m[1], +m[2] - 1, +m[3])); return `${DAYS[d.getUTCDay()]}, ${MONTHS[d.getUTCMonth()]} ${d.getUTCDate()}`; } /** A real calendar date written YYYY-MM-DD ("2026-10-32" is not one). */ export function isRealDate(iso: string): boolean { const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso.trim()); if (!m) return false; const d = new Date(Date.UTC(+m[1], +m[2] - 1, +m[3])); return d.getUTCFullYear() === +m[1] && d.getUTCMonth() === +m[2] - 1 && d.getUTCDate() === +m[3]; } export function firstName(fullName: string): string { return fullName.trim().split(/\s+/)[0] ?? ""; } /** A short, stable fingerprint of the letter text, stored with each attempt. */ export function letterVersion(t: LetterTemplate): string { let h = 5381; const s = `${t.subject}\u0000${t.body}`; for (let i = 0; i < s.length; i++) h = ((h << 5) + h + s.charCodeAt(i)) >>> 0; return `v-${h.toString(36)}`; } export function renderLetter( t: LetterTemplate, a: { therapist: string; startDate: string; welcomeEmail: string }, ): OutgoingLetter { const fill = (s: string) => s.replace(/\{\{\s*first_name\s*\}\}/g, firstName(a.therapist)).replace(/\{\{\s*start_date\s*\}\}/g, longDate(a.startDate)); return { to: a.welcomeEmail.trim(), subject: fill(t.subject), body: fill(t.body), senderName: t.senderName, replyTo: t.replyTo, }; }