// commands/callReport.js import { DateTime } from 'luxon'; import { logger } from '../utils/logger.js'; import { collectCallReport } from '../services/callReport/callReportService.js'; import { renderCallReportMarkdown } from '../services/renderers/callReportRenderer.js'; import { parseCallReportTarget } from '../services/callReport/parseTarget.js'; function pickDateArg(args) { const targetParsed = parseCallReportTarget(args[0]); for (let i = 1; i < args.length; i++) { const a = String(args[i] || '').trim(); if (!a || a.startsWith('--')) continue; if (i === 1 && targetParsed?.kind === 'store' && /^\d{2,4}$/.test(a)) continue; return a; } const flag = args.find((a) => String(a).startsWith('--date=')); if (flag) return flag.split('=').slice(1).join('='); const idx = args.indexOf('--date'); if (idx >= 0 && args[idx + 1]) return args[idx + 1]; return null; } function hasDetailFlag(args, query) { return args.some((a) => ['detail', 'detailed', '--detail', '--detailed'].includes(String(a).toLowerCase())) || query.detail === 'true' || query.detailed === 'true'; } function formatQueuedRunAt(runAt) { return DateTime.fromJSDate(runAt).toFormat('h:mm:ss a'); } function pickTargetArg(args, query) { return args[0]?.trim() || query.target || query.storeNum || query.store || query.email || query.number || query.s || null; } function usageMarkdown() { return ( '**Call report usage**\n\n' + '`/callreport ` — yesterday 9am–9pm local (default)\n' + '`/callreport ` — calls for that user at their location\n' + '`/callreport ` — calls for that assigned number\n' + '`/callreport today` — today 9am → 5 min ago\n' + '`/callreport 2026-07-22` — specific day\n' + '`/callreport --detail` — include per-call table\n\n' + 'HTTP: `?target=782&date=yesterday&detail=true` (also `storeNum`, `email`, `number`)' ); } function ackLabel(target) { if (!target) return 'target'; if (target.kind === 'store') return `store **${target.storeNum}**`; if (target.locationName) return `**${target.label}** (${target.locationName})`; return `**${target.label}**`; } export async function handleCallReport(bot, trigger) { logger('callreport', 'Handler entered', 'debug'); const query = trigger.query || {}; const args = trigger.args || []; const targetToken = pickTargetArg(args, query); const dateArg = pickDateArg(args) || query.date || null; const detail = hasDetailFlag(args, query); if (!targetToken || !parseCallReportTarget(targetToken)) { await bot.say('markdown', usageMarkdown()); return; } await bot.say( 'markdown', `**Call report** — generating for ${ackLabel({ label: targetToken })} (${dateArg || 'yesterday'})…`, ); let cdrQueuedNoticeSent = false; try { const report = await collectCallReport(targetToken, { dateArg, onCdrQueued: async ({ runAt, waitMs }) => { if (cdrQueuedNoticeSent) return; cdrQueuedNoticeSent = true; const secs = Math.max(1, Math.ceil(waitMs / 1000)); await bot.say( 'markdown', `⏳ **Call report** — CDR query queued. Webex allows one \`cdr_feed\` request per ~90 seconds. ` + `Your request will run at **${formatQueuedRunAt(runAt)}** (~${secs}s).`, ); }, }); const md = renderCallReportMarkdown(report, { detail }); await bot.say('markdown', md); } catch (err) { logger('callreport', `Failed for target ${targetToken}: ${err.message}`, 'error'); await bot.say('markdown', `❌ Call report failed for **${targetToken}**: ${err.message}`); } }