import assert from "node:assert/strict"
import { rememberServerIfaces, resetIfaceCacheForTests } from "./traffic-flow-ifindex.js"
import {
  ingestParsedFlowsForServerForTests,
  resetFlowRingsForTests,
} from "./traffic-flow-ingest.js"
import { buildFlowMapHops } from "./traffic-flow-map-hops.js"
import { seedFlowTopologyForTests, type FlowTopology } from "./traffic-flow-topology.js"
import { disableCatalogFetchForTests, resetFlowCatalogForTests } from "./traffic-flow-classify.js"
import {
  disableRipeEnqueueForTests,
  disableRipePersistForTests,
  resetRipeCacheForTests,
} from "./traffic-flow-ripe.js"

disableCatalogFetchForTests()
resetFlowCatalogForTests()
disableRipePersistForTests()
resetRipeCacheForTests()
disableRipeEnqueueForTests()

const topo: FlowTopology = {
  clientIfaces: new Map([[7, new Set(["gre-client"])]]),
  clientByIface: new Map([["7|gre-client", {
    userId: "u1",
    login: "alice",
    name: "Alice",
    serverId: 7,
    interfaceName: "gre-client",
  }]]),
  enNodes: [{ id: 9, name: "NSK-EN", hosts: ["198.51.100.1"] }],
  enHosts: new Set(["198.51.100.1"]),
  jhHosts: new Set(["203.0.113.10"]),
  wanIfaces: new Map([[3, new Set(["ether1-rt"])]]),
  plane: {
    clientIfaceNames: new Set(["gre-client"]),
    enHosts: new Set(["198.51.100.1"]),
    jhHosts: new Set(["203.0.113.10"]),
  },
}

resetFlowRingsForTests()
resetIfaceCacheForTests()
seedFlowTopologyForTests(topo)
rememberServerIfaces(7, [
  { ".id": "*2", name: "gre-client" },
  { ".id": "*3", name: "gre-jh-en" },
  { ".id": "*A", name: "wg-flow" },
])
rememberServerIfaces(3, [
  { ".id": "*1", name: "ether1-rt" },
])

ingestParsedFlowsForServerForTests(7, [
  {
    src: "10.100.1.17",
    dst: "8.8.8.8",
    proto: 6,
    srcPort: 51234,
    dstPort: 443,
    bytes: 12_000,
    packets: 10,
    inIface: "2",
    outIface: "3",
    nextHop: "198.51.100.1",
  },
  {
    src: "203.0.113.10",
    dst: "198.51.100.1",
    proto: 47,
    srcPort: 0,
    dstPort: 0,
    bytes: 5_000_000,
    packets: 4000,
    inIface: "3",
    outIface: "3",
  },
  {
    src: "10.100.1.17",
    dst: "10.100.1.18",
    proto: 6,
    srcPort: 50000,
    dstPort: 443,
    bytes: 8000,
    packets: 8,
    inIface: "2",
    outIface: "2",
  },
  {
    src: "10.255.254.1",
    dst: "10.255.254.2",
    proto: 17,
    srcPort: 4739,
    dstPort: 2055,
    bytes: 400,
    packets: 2,
    inIface: "10",
    outIface: "",
  },
])
ingestParsedFlowsForServerForTests(3, [
  {
    src: "192.168.1.10",
    dst: "8.8.4.4",
    proto: 6,
    srcPort: 40000,
    dstPort: 443,
    bytes: 3000,
    packets: 4,
    inIface: "1",
    outIface: "1",
  },
])

try {
  const def = buildFlowMapHops({ minutes: 5 })
  assert.equal(def.excludeOverlayApplied, true)
  assert.equal(def.excludeMeshApplied, true)
  assert.equal(def.dedupApplied, true)
  assert.equal(def.windowSec, 300)

  const payloadGre = def.hops.find((h) => h.kind === "gre" && h.fromId === "7" && h.toId === "9")
  assert.ok(payloadGre, "payload JH→EN hop")
  assert.equal(payloadGre.bytes, 12_000)
  assert.equal(payloadGre.bps, (12_000 * 8) / 300)
  assert.equal(payloadGre.bpsFwd, (12_000 * 8) / 300)
  assert.equal(payloadGre.iface, "gre-jh-en")

  const greIface = def.hops.find((h) => h.kind === "iface" && h.iface === "gre-jh-en" && h.fromId === "7")
  assert.ok(greIface)
  assert.equal(greIface.bytes, 12_000)
  assert.equal(greIface.bpsFwd, (12_000 * 8) / 300)

  assert.ok(!def.hops.some((h) => h.bytes >= 5_000_000), "overlay GRE proto 47 excluded")
  assert.ok(!def.hops.some((h) => h.iface === "wg-flow"), "mgmt wg-flow excluded")
  const clientIngress = def.hops.find((h) => h.iface === "gre-client" && h.fromId === "7" && h.kind === "iface")
  assert.ok(clientIngress, "payload ingress on client iface")
  assert.equal(clientIngress.bytes, 12_000)

  const wan = def.hops.find((h) => h.kind === "wan" && h.fromId === "3" && h.iface === "ether1-rt")
  assert.ok(wan, "WAN hop from home-router")
  assert.equal(wan.bytes, 3000)

  const withAll = buildFlowMapHops({ minutes: 5, excludeOverlay: false, excludeMesh: false })
  const overlayIface = withAll.hops.find((h) => h.iface === "gre-jh-en" && h.fromId === "7")
  assert.ok(overlayIface && overlayIface.bytes >= 5_000_000)
  const meshIface = withAll.hops.find((h) => h.iface === "gre-client" && h.fromId === "7" && h.kind === "iface")
  assert.ok(meshIface && meshIface.bytes >= 20_000)
} finally {
  seedFlowTopologyForTests(null)
  resetFlowRingsForTests()
  resetIfaceCacheForTests()
  resetRipeCacheForTests()
  resetFlowCatalogForTests()
}

console.log("traffic-flow-map-hops.test.ts: ok")
