import { businessConfig } from "@/lib/seo-config" import { isEmailConfigured, sendTransactionalEmail } from "@/lib/email" export type AdminPhoneCallTurn = { id: string role: string text: string source?: string kind?: string createdAt: number } export type AdminPhoneCallDetail = { call: { id: string roomName: string participantIdentity: string callerPhone?: string pathname?: string pageUrl?: string source?: string contactProfileId?: string contactDisplayName?: string contactCompany?: string startedAt: number endedAt?: number durationMs: number | null callStatus: "started" | "completed" | "failed" transcriptTurnCount: number answered: boolean agentAnsweredAt?: number linkedLeadId?: string leadOutcome: "none" | "contact" | "requestMachine" handoffRequested: boolean handoffReason?: string summaryText?: string notificationStatus: "pending" | "sent" | "failed" | "disabled" notificationSentAt?: number notificationError?: string reminderStatus?: "none" | "scheduled" | "sameDay" reminderRequestedAt?: number reminderStartAt?: number reminderEndAt?: number reminderCalendarEventId?: string reminderCalendarHtmlLink?: string reminderNote?: string warmTransferStatus?: "none" | "attempted" | "connected" | "failed" | "fallback" warmTransferTarget?: string warmTransferAttemptedAt?: number warmTransferConnectedAt?: number warmTransferFailureReason?: string recordingStatus?: | "pending" | "starting" | "recording" | "completed" | "failed" recordingUrl?: string recordingError?: string } linkedLead: null | { id: string type: "contact" | "requestMachine" status: "pending" | "delivered" | "failed" firstName: string lastName: string email: string phone: string company?: string intent?: string message?: string createdAt: number } contactProfile: null | { _id: string normalizedPhone: string displayName?: string firstName?: string lastName?: string email?: string company?: string lastIntent?: string lastLeadOutcome?: "none" | "contact" | "requestMachine" lastSummaryText?: string lastCallAt?: number lastReminderAt?: number reminderNotes?: string } turns: AdminPhoneCallTurn[] } export function formatPhoneCallTimestamp(timestamp?: number) { if (!timestamp) { return "—" } return new Date(timestamp).toLocaleString("en-US", { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }) } export function formatPhoneCallDuration(durationMs: number | null | undefined) { if (typeof durationMs !== "number" || durationMs <= 0) { return "—" } const totalSeconds = Math.round(durationMs / 1000) const minutes = Math.floor(totalSeconds / 60) const seconds = totalSeconds % 60 return `${minutes}:${String(seconds).padStart(2, "0")}` } export function normalizePhoneFromIdentity(identity?: string) { const digits = String(identity || "").replace(/\D/g, "") if (!digits) { return "" } if (digits.length === 10) { return `+1${digits}` } if (digits.length === 11 && digits.startsWith("1")) { return `+${digits}` } return `+${digits}` } export function buildPhoneCallSummary( detail: Pick ) { const answeredLabel = detail.call.answered ? "Jessica answered the call." : "Jessica did not fully answer the call." const leadLabel = detail.call.leadOutcome === "none" ? "No lead was submitted." : detail.call.leadOutcome === "requestMachine" ? "A machine request lead was submitted." : "A contact lead was submitted." const lastMeaningfulUserTurn = [...detail.turns] .reverse() .find((turn) => turn.role === "user" && turn.text.trim()) const leadMessage = detail.linkedLead?.message?.trim() || detail.linkedLead?.intent?.trim() || lastMeaningfulUserTurn?.text.trim() || "" const callerNumber = detail.call.callerPhone || normalizePhoneFromIdentity(detail.call.participantIdentity) || detail.call.participantIdentity const parts = [ `Caller: ${detail.call.contactDisplayName || callerNumber || "Unknown caller"}.`, answeredLabel, leadLabel, ] if (detail.call.contactCompany) { parts.push(`Company: ${detail.call.contactCompany}.`) } if (detail.call.handoffRequested) { parts.push( `Human escalation requested${detail.call.handoffReason ? `: ${detail.call.handoffReason}.` : "."}` ) } if (detail.call.reminderStatus === "sameDay") { parts.push("A same-day follow-up reminder was created for Matt.") } else if (detail.call.reminderStatus === "scheduled") { parts.push( `A follow-up reminder was scheduled for ${formatPhoneCallTimestamp(detail.call.reminderStartAt)}.` ) } if (detail.call.warmTransferStatus && detail.call.warmTransferStatus !== "none") { parts.push( `Warm transfer status: ${detail.call.warmTransferStatus}${detail.call.warmTransferFailureReason ? ` (${detail.call.warmTransferFailureReason})` : ""}.` ) } if (leadMessage) { parts.push(`Topic: ${leadMessage.replace(/\s+/g, " ").slice(0, 220)}.`) } return parts.join(" ") } export async function sendPhoneCallSummaryEmail(args: { detail: AdminPhoneCallDetail adminUrl: string }) { const adminEmail = String(process.env.ADMIN_EMAIL || "") .trim() .toLowerCase() const fromEmail = String( process.env.PHONE_CALL_SUMMARY_FROM_EMAIL || "" ).trim() if (!adminEmail || !fromEmail || !isEmailConfigured()) { const missing = [ !adminEmail ? "ADMIN_EMAIL" : null, !fromEmail ? "PHONE_CALL_SUMMARY_FROM_EMAIL" : null, !isEmailConfigured() ? "email transport" : null, ].filter(Boolean) return { status: "disabled" as const, error: `${missing.join(", ")} is not configured.`, } } const callUrl = `${args.adminUrl.replace(/\/$/, "")}/admin/calls/${args.detail.call.id}` const summaryText = buildPhoneCallSummary(args.detail) const callerNumber = args.detail.call.callerPhone || normalizePhoneFromIdentity(args.detail.call.participantIdentity) || "Unknown caller" const callerLabel = args.detail.call.contactDisplayName || callerNumber const statusLabel = args.detail.call.callStatus.toUpperCase() const transcriptHtml = args.detail.turns .slice(-6) .map((turn) => { const role = turn.role.replace(/[<>&"]/g, "") const text = turn.text .replace(/&/g, "&") .replace(//g, ">") return `
  • ${role}: ${text}
  • ` }) .join("") const html = `

    Rocky Mountain Vending phone call summary

    Caller: ${callerLabel}

    Caller number: ${callerNumber}

    Company: ${args.detail.call.contactCompany || "Unknown"}

    Started: ${formatPhoneCallTimestamp(args.detail.call.startedAt)}

    Duration: ${formatPhoneCallDuration(args.detail.call.durationMs)}

    Call status: ${statusLabel}

    Jessica answered: ${args.detail.call.answered ? "Yes" : "No"}

    Lead outcome: ${args.detail.call.leadOutcome}

    Handoff requested: ${args.detail.call.handoffRequested ? "Yes" : "No"}

    Reminder status: ${args.detail.call.reminderStatus || "none"}

    Reminder time: ${formatPhoneCallTimestamp(args.detail.call.reminderStartAt)}

    Reminder link: ${ args.detail.call.reminderCalendarHtmlLink ? `${args.detail.call.reminderCalendarHtmlLink}` : "No reminder link" }

    Warm transfer: ${args.detail.call.warmTransferStatus || "none"}

    Warm transfer details: ${args.detail.call.warmTransferFailureReason || "—"}

    Recording status: ${args.detail.call.recordingStatus || "Unavailable"}

    Recording URL: ${ args.detail.call.recordingUrl ? `${args.detail.call.recordingUrl}` : "Not available in RMV admin" }

    Summary: ${summaryText}

    Admin call detail: ${callUrl}

    Linked lead: ${args.detail.linkedLead?.id || "None"}

    Recent transcript

    ` try { await sendTransactionalEmail({ from: fromEmail, to: adminEmail, subject: `[RMV Phone] ${statusLabel} call from ${callerLabel}`, html, }) return { status: "sent" as const, error: undefined, } } catch (error) { return { status: "failed" as const, error: error instanceof Error ? error.message : "Failed to send phone call summary email.", } } } export function buildFallbackPhoneCallUrl(callId: string) { return `${businessConfig.website.replace(/\/$/, "")}/admin/calls/${callId}` }