/** Mirrors backend terminationJointReviewRound.util.ts — keep send-back / reconsider detection aligned. */ const norm = (s: string | undefined | null) => String(s || '') .toLowerCase() .replace(/\s+/g, ' ') .trim(); const SCN_CANONICAL = 'Evaluation of Dealer SCN Response'; export const isScnResponseJointTargetStage = (targetStage: string | undefined | null): boolean => { const n = norm(targetStage); if (!n) return false; if (n === norm(SCN_CANONICAL)) return true; if (n.includes('evaluation') && n.includes('scn') && n.includes('response')) return true; if (n.includes('personal hearing')) return true; return false; }; export const isRbmJointTargetStage = (targetStage: string | undefined | null): boolean => { const n = norm(targetStage); return n.includes('rbm') && (n.includes('dd-zm') || n.includes('dd zm')); }; function isSendBackOrReconsiderTimelineAction(action: string | undefined | null): boolean { const a = norm(action); return ( a.includes('sent back') || a.includes('send back') || a.includes('reconsider') || a.includes('reconsideration') ); } export type JointRoundTimelineMode = 'scn_response_eval' | 'rbm_review'; export function getJointRoundCutoffMsFromTimeline( timeline: unknown, mode: JointRoundTimelineMode ): number | null { if (!Array.isArray(timeline) || timeline.length === 0) return null; const matcher = mode === 'scn_response_eval' ? isScnResponseJointTargetStage : isRbmJointTargetStage; const arr = timeline as Record[]; for (let i = arr.length - 1; i >= 0; i--) { const e = arr[i]; if (!isSendBackOrReconsiderTimelineAction(e?.action as string)) continue; if (!matcher(e?.targetStage as string)) continue; const t = e?.timestamp != null ? new Date(e.timestamp as string | number | Date).getTime() : NaN; if (!Number.isNaN(t)) return t; } return null; } export function auditLogTimestampMs(log: { createdAt?: string | Date; timestamp?: string | Date }): number { const raw = log.createdAt ?? log.timestamp; if (raw == null) return 0; const t = new Date(raw).getTime(); return Number.isNaN(t) ? 0 : t; } export function isAuditLogInCurrentJointRound(log: { createdAt?: string | Date; timestamp?: string | Date }, cutoffMs: number | null): boolean { if (cutoffMs == null) return true; return auditLogTimestampMs(log) >= cutoffMs; }