import {z} from "zod" import {ospfOptimizeSchema} from "./ospf-response" import {filtersResponseSchema} from "./filters-response" const unique = (rows:T[],key:(row:T)=>string|number)=>new Set(rows.map(key)).size===rows.length const measured = z.number().finite().nonnegative().nullable() export const optimizerServersSchema=z.array(z.object({ id:z.number().int().positive(),name:z.string(),host:z.string().min(1),type:z.enum(["home-router","jump-host","exit-node"]), enabled:z.boolean(),country:z.string(),site:z.string().optional().default(""), status:z.enum(["online","offline","degraded"]).nullable().optional().default(null), latency:measured.optional().default(null),model:z.string().nullable().optional().default(null), wanUplinks:z.array(z.object({id:z.string().min(1),name:z.string(),isp:z.string(),iface:z.string(),ip:z.string(),maxDl:z.number().finite().positive(),maxUl:z.number().finite().positive()})).refine(rows=>unique(rows,row=>row.id)).optional(), })).refine(rows=>unique(rows,row=>row.id)) export const optimizerRulesSchema=filtersResponseSchema.refine(data=>data.stale!==true) export const optimizerProbesSchema=z.object({probes:z.array(z.object({ id:z.string().min(1),srcServerId:z.string().min(1),dstServerId:z.string().min(1),srcInterface:z.string(),dstInterface:z.string(),enabled:z.boolean(), lastPingRttMs:measured,lastPingLossPct:z.number().finite().min(0).max(100).nullable(), lastTxAvgMbps:measured,lastRxAvgMbps:measured,lastPingAt:z.string().datetime({offset:true}).nullable(), })).refine(rows=>unique(rows,row=>row.id))}) export const optimizerOspfPreviewSchema=z.object({ serverId:z.number().int().positive(),serverName:z.string(),pingWeight:z.number().int().min(0).max(100), interfacesTotal:z.number().int().nonnegative(),changedCount:z.number().int().nonnegative(),unchangedCount:z.number().int().nonnegative(), interfaces:ospfOptimizeSchema.shape.interfaces,changes:ospfOptimizeSchema.shape.interfaces, }).refine(data=>{ const changed=data.interfaces.filter(row=>row.currentCost!==row.optimalCost) return data.interfacesTotal===data.interfaces.length && data.changedCount===data.changes.length && data.unchangedCount===data.interfacesTotal-data.changedCount && new Set(data.interfaces.map(row=>row.id)).size===data.interfaces.length && new Set(data.changes.map(row=>row.id)).size===data.changes.length && changed.length===data.changes.length && changed.every(row=>data.changes.some(change=>JSON.stringify(change)===JSON.stringify(row))) }) export type OptimizerOspfPreview=z.infer