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; pathname?: string; pageUrl?: string; source?: 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; 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; }; 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 = normalizePhoneFromIdentity(detail.call.participantIdentity) || detail.call.participantIdentity; const parts = [ `Caller: ${callerNumber || "Unknown caller"}.`, answeredLabel, leadLabel, ]; if (detail.call.handoffRequested) { parts.push(`Human escalation requested${detail.call.handoffReason ? `: ${detail.call.handoffReason}.` : "."}`); } 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 = normalizePhoneFromIdentity(args.detail.call.participantIdentity) || "Unknown caller"; 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: ${callerNumber}

    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"}

    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 ${callerNumber}`, 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}`; }