import type { CanvasNode } from "@/types/canvas"; export type PendingCanvasAgentTarget = { nodeId?: string | null; requestedAt?: number | null; }; const DEFAULT_PENDING_TARGET_MAX_AGE_MS = 10 * 60 * 1000; function normalizeNodeId(value: unknown) { return typeof value === "string" ? value.trim() : ""; } export function resolvePendingCanvasAgentTargetNode(params: { nodes: CanvasNode[]; pendingTarget?: PendingCanvasAgentTarget | null; now?: number; maxAgeMs?: number; isEligibleNode?: (node: CanvasNode) => boolean; }) { const nodeId = normalizeNodeId(params.pendingTarget?.nodeId); if (!nodeId) return null; const requestedAt = Number(params.pendingTarget?.requestedAt || 0); const now = Number(params.now ?? Date.now()); const maxAgeMs = Math.max( 0, Number(params.maxAgeMs ?? DEFAULT_PENDING_TARGET_MAX_AGE_MS) ); if ( Number.isFinite(requestedAt) && requestedAt > 0 && Number.isFinite(now) && now - requestedAt > maxAgeMs ) { return null; } const node = params.nodes.find((item) => item.id === nodeId) || null; if (!node) return null; if (params.isEligibleNode && !params.isEligibleNode(node)) return null; return node; } export function mergePendingCanvasAgentTargetNodeIds(params: { selectedNodeIds: string[]; pendingTargetNodeId?: string | null; maxItems?: number; }) { const maxItems = Math.max(1, Number(params.maxItems || 20)); return Array.from( new Set( [ ...params.selectedNodeIds, normalizeNodeId(params.pendingTargetNodeId), ].filter(Boolean) ) ).slice(0, maxItems); }