import { protoName } from "./traffic-flow-parse.js"

const WELL_KNOWN: Record<string, string> = {
  "6:80": "HTTP",
  "6:443": "HTTPS",
  "6:8080": "HTTP-alt",
  "6:8443": "HTTPS-alt",
  "6:22": "SSH",
  "6:21": "FTP",
  "6:25": "SMTP",
  "6:110": "POP3",
  "6:143": "IMAP",
  "6:993": "IMAPS",
  "6:995": "POP3S",
  "6:587": "SMTP",
  "6:465": "SMTPS",
  "6:3306": "MySQL",
  "6:5432": "PostgreSQL",
  "6:6379": "Redis",
  "6:3389": "RDP",
  "6:445": "SMB",
  "6:139": "NetBIOS",
  "6:179": "BGP",
  "6:8291": "WinBox",
  "6:8728": "ROS-API",
  "6:8729": "ROS-API-SSL",
  "17:53": "DNS",
  "6:53": "DNS",
  "17:123": "NTP",
  "17:161": "SNMP",
  "17:162": "SNMP-trap",
  "17:500": "IKE",
  "17:4500": "NAT-T",
  "17:1194": "OpenVPN",
  "17:443": "QUIC",
  "17:853": "DNS",
  "6:853": "DNS",
  "17:51820": "WireGuard",
  "17:13232": "WireGuard",
  "17:51821": "WireGuard",
  "17:4789": "VXLAN",
  "17:4739": "IPFIX",
  "17:2055": "NetFlow",
  "17:67": "DHCP",
  "17:68": "DHCP",
  "17:69": "TFTP",
  "17:1812": "RADIUS",
  "1:0": "ICMP",
  "47:0": "GRE",
  "50:0": "ESP",
  "89:0": "OSPF",
}

export function applicationName(proto: number, dstPort: number, srcPort = 0): string {
  if (proto === 1) return "ICMP"
  if (proto === 47) return "GRE"
  if (proto === 50) return "ESP"
  if (proto === 89) return "OSPF"
  if (proto === 17 && (dstPort === 443 || srcPort === 443)) return "QUIC"
  const dstKey = `${proto}:${dstPort}`
  const srcKey = `${proto}:${srcPort}`
  return WELL_KNOWN[dstKey] ?? WELL_KNOWN[srcKey] ?? `${protoName(proto)}/${dstPort || srcPort || "—"}`
}

export interface FlowMatchQuery {
  serverId?: number
  userId?: string
  iface?: string
}

export function flowRowMatchesFilter(
  row: { serverId: number; inIface: string },
  resolvedName: string,
  q: FlowMatchQuery,
  allow: Map<number, Set<string>> | null,
): boolean {
  if (q.serverId != null && row.serverId !== q.serverId) return false
  if (allow) {
    const names = allow.get(row.serverId)
    if (!names || !names.has(resolvedName)) return false
  }
  const iface = q.iface && q.iface !== "__all__" ? q.iface : ""
  if (iface && resolvedName !== iface && row.inIface !== iface) return false
  return true
}
