import { Injectable, Logger } from '@nestjs/common'; import { PlatformGraphqlService } from '../platform/platform-graphql.service'; export type WorklistResponse = { missedCalls: any[]; followUps: any[]; marketingLeads: any[]; totalPending: number; }; @Injectable() export class WorklistService { private readonly logger = new Logger(WorklistService.name); constructor(private readonly platform: PlatformGraphqlService) {} async getWorklist( agentName: string, authHeader: string, ): Promise { const [missedCalls, followUps, marketingLeads] = await Promise.all([ this.getMissedCalls(agentName, authHeader), this.getPendingFollowUps(agentName, authHeader), this.getAssignedLeads(agentName, authHeader), ]); return { missedCalls, followUps, marketingLeads, totalPending: missedCalls.length + followUps.length + marketingLeads.length, }; } private async getAssignedLeads( agentName: string, authHeader: string, ): Promise { try { const data = await this.platform.queryWithAuth( `{ leads(first: 20, filter: { assignedAgent: { eq: "${agentName}" } }, orderBy: [{ createdAt: AscNullsLast }]) { edges { node { id createdAt contactName { firstName lastName } contactPhone { primaryPhoneNumber } contactEmail { primaryEmail } source status interestedService assignedAgent campaignId contactAttempts spamScore isSpam aiSummary aiSuggestedAction } } } }`, undefined, authHeader, ); return data.leads.edges.map((e: any) => e.node); } catch (err) { this.logger.warn(`Failed to fetch assigned leads: ${err}`); return []; } } private async getPendingFollowUps( agentName: string, authHeader: string, ): Promise { try { const data = await this.platform.queryWithAuth( `{ followUps(first: 20, filter: { assignedAgent: { eq: "${agentName}" } }) { edges { node { id name createdAt typeCustom status scheduledAt completedAt priority assignedAgent patientId } } } }`, undefined, authHeader, ); // Filter to PENDING/OVERDUE client-side since platform may not support in-filter on remapped fields return data.followUps.edges .map((e: any) => e.node) .filter((f: any) => f.status === 'PENDING' || f.status === 'OVERDUE'); } catch (err) { this.logger.warn(`Failed to fetch follow-ups: ${err}`); return []; } } private async getMissedCalls( agentName: string, authHeader: string, ): Promise { try { // FIFO ordering (AscNullsLast) — oldest first. No agentName filter — missed calls are a shared queue. const data = await this.platform.queryWithAuth( `{ calls(first: 20, filter: { callStatus: { eq: MISSED }, callbackstatus: { in: [PENDING_CALLBACK, CALLBACK_ATTEMPTED] } }, orderBy: [{ startedAt: AscNullsLast }]) { edges { node { id name createdAt direction callStatus agentName callerNumber { primaryPhoneNumber } startedAt endedAt durationSec disposition leadId callbackstatus callsourcenumber missedcallcount callbackattemptedat } } } }`, undefined, authHeader, ); return data.calls.edges.map((e: any) => e.node); } catch (err) { this.logger.warn(`Failed to fetch missed calls: ${err}`); return []; } } }