// services/voicePin/resolveVmPinTarget.js // Parse and resolve /resetvmpin targets: email, store (2–4 digits), or extension (5 digits). import { logger } from '../../utils/logger.js'; import { getPersonDetails } from '../phoneService.js'; import { resolvePersonLocation, resolveRecordsByExtension, } from '../callTest/locationResolver.js'; export { parseVmPinTarget } from './parseVmPinTarget.js'; const LOG_SCOPE = 'resetvmpin:resolve'; /** * @typedef {'email'|'store'|'extension'} VmPinMatchSource */ async function getWebex() { const mod = await import('../../integrations/webex/WebexClient.js'); return mod.default; } async function fetchVoicemailSnapshot(personId) { if (!personId) return { enabled: null }; try { const webex = await getWebex(); const vm = await webex.request('GET', `people/${personId}/features/voicemail`); return { enabled: vm?.enabled === true, raw: vm }; } catch (err) { logger(LOG_SCOPE, `Voicemail feature fetch failed for ${personId}: ${err.message}`, 'warn'); return { enabled: null }; } } /** * Resolve a parsed VM PIN target to a Webex person + context for the confirmation card. * * @param {ReturnType} parsed * @returns {Promise} */ export async function resolveVmPinTarget(parsed) { if (!parsed) { throw new Error('Invalid target. Use email, 2–4 digit store number, or 5-digit extension.'); } const webex = await getWebex(); let personId = null; let email = null; let matchSource; let storeNum = null; let extension = null; let numberRecord = null; if (parsed.kind === 'email') { matchSource = 'email'; email = parsed.email; const person = await webex.findPersonByEmail(email); if (!person) { throw new Error(`No Webex person found for ${email}`); } personId = person.id; } else if (parsed.kind === 'store') { matchSource = 'store'; storeNum = parsed.storeNum; const padded = storeNum.padStart(5, '0'); email = `ae${padded}@ae.com`; const person = await webex.findPersonByEmail(email); if (!person) { throw new Error(`No Webex person found for store ${storeNum} (${email})`); } personId = person.id; } else { matchSource = 'extension'; extension = parsed.extension; const records = await resolveRecordsByExtension(extension); if (records.length === 0) { throw new Error(`No telephony number found for extension ${extension}`); } const ownerIds = [...new Set(records.map((r) => r.owner?.id).filter(Boolean))]; if (ownerIds.length !== 1) { throw new Error( `Extension ${extension} matches ${records.length} number(s) across ${ownerIds.length} owner(s) — cannot resolve a unique user`, ); } personId = ownerIds[0]; numberRecord = records[0]; } const [person, locationInfo, voicemail] = await Promise.all([ getPersonDetails(personId), resolvePersonLocation(personId), fetchVoicemailSnapshot(personId), ]); if (!person) { throw new Error(`Could not load Webex person ${personId}`); } if (!email) { email = (person.emails || []).find((e) => typeof e === 'string' && e.includes('@')) || person.emails?.[0]?.value || person.emails?.[0] || null; } const ownedNumbers = locationInfo?.ownedNumbers || []; const primaryNumber = numberRecord || ownedNumbers.find((n) => n.extension === extension) || ownedNumbers[0] || null; return { personId, person, email: email || person.displayName || personId, displayName: person.displayName || email || personId, matchSource, storeNum, extension: extension || primaryNumber?.extension || null, locationId: locationInfo?.locationId || primaryNumber?.locationId || null, locationName: locationInfo?.locationName || primaryNumber?.locationName || null, mainNumber: primaryNumber?.phoneNumber || null, voicemailEnabled: voicemail.enabled, }; }