import type { PingProbe, Server } from "@/lib/data" /** Длина ряда на графике дашборда (ось времени). */ export const DASH_LATENCY_POINTS = 60 export interface DashboardLatencyChartInput { series: Record labels: Record } /** * Средний RTT по измеренным общим корзинам включённых проб одного источника. * Не интерполируем и не подменяем отсутствующие измерения нулями. * Ключ серии — стабильный id вида `src-`; подпись — площадка или имя сервера. * Ограничение числа линий — чтобы график оставался читаемым. */ export function buildLatencySeriesByProbeSource( probes: Array&{series:(number|null)[]}>, servers: Server[], opts?: { maxServers?: number; points?: number }, ): DashboardLatencyChartInput { const maxServers = opts?.maxServers ?? 8 const points = opts?.points ?? DASH_LATENCY_POINTS const bySrv = new Map&{series:(number|null)[]}>>() for (const p of probes) { if (!p.enabled || !p.series?.length) continue const sid = p.srcServerId if (!bySrv.has(sid)) bySrv.set(sid, []) bySrv.get(sid)!.push(p) } const sortedIds = [...bySrv.keys()].sort((a, b) => { const na = servers.find((s) => s.id === a)?.name ?? a const nb = servers.find((s) => s.id === b)?.name ?? b return na.localeCompare(nb, "ru") }).slice(0, maxServers) const series: Record = {} const labels: Record = {} for (const sid of sortedIds) { const plist = bySrv.get(sid)! const innerLen = plist.reduce((m, p) => Math.max(m, p.series.length), 0) if (innerLen === 0) continue const averaged = Array.from({ length: Math.min(innerLen,points) }, (_, i) => { const vals=plist.map(p=>p.series[i]) if(vals.some(v=>typeof v!=="number"||!Number.isFinite(v)))return null const mean=vals.reduce((sum,v)=>sum+(v??0),0)/vals.length return Number.isFinite(mean)?Math.round(mean):null }) if(!averaged.some(v=>v!==null))continue const key = "src-"+sid series[key] = averaged const srv = servers.find((s) => s.id === sid) const site = srv?.site?.trim() labels[key] = site && site !== "—" ? site.slice(0, 16) : (srv?.name ?? `#${sid}`).slice(0, 16) } return { series, labels } }