import { servers } from "../db/schema.js"
import type { BgpSessionRead, RosBgpSession } from "../types/server.js"

type ServerRow = typeof servers.$inferSelect

/** Parse RouterOS duration like "1m30s", "1d5h13m23s580ms", "30s" → seconds */
function parseDuration(s: string | undefined): number {
  if (!s) return 0
  let total = 0
  const matches = s.matchAll(/(\d+)(w|d|h|m(?!s)|s|ms)/g)
  for (const m of matches) {
    const n = parseInt(m[1])
    switch (m[2]) {
      case "w":
        total += n * 604800
        break
      case "d":
        total += n * 86400
        break
      case "h":
        total += n * 3600
        break
      case "m":
        total += n * 60
        break
      case "s":
        total += n
        break
      default:
        break
    }
  }
  return total
}

function parseCapabilities(capStr: string | undefined): string[] {
  if (!capStr) return []
  const codeMap: Record<string, string> = {
    mp: "MP-BGP",
    rr: "Route Refresh",
    gr: "Graceful Restart",
    as4: "4-byte-AS",
    enhe: "Extended Next-Hop",
    role: "BGP Role",
    err: "Extended Route Refresh",
    llgr: "Long-Lived GR",
    "add-path": "ADD-PATH",
  }
  return capStr
    .split(",")
    .map((c) => c.trim().toLowerCase())
    .filter(Boolean)
    .map((c) => codeMap[c] ?? c)
    .filter((v, i, a) => a.indexOf(v) === i)
}

function detectState(s: RosBgpSession): string {
  if (s["established"] === "true") return "Established"

  if (s["state"]) {
    const map: Record<string, string> = {
      established: "Established",
      active: "Active",
      idle: "Idle",
      connect: "Connect",
      opensent: "OpenSent",
      openconfirm: "OpenConfirm",
      "open sent": "OpenSent",
      "open confirm": "OpenConfirm",
    }
    const key = s["state"].trim().toLowerCase()
    if (map[key]) return map[key]
    for (const [k, v] of Object.entries(map)) {
      if (key.startsWith(k)) return v
    }
    return key.charAt(0).toUpperCase() + key.slice(1)
  }

  if (s["uptime"]) return "Active"

  return "Idle"
}

/** Парсинг BGP-сессий с роутера — общая логика для HTTP-маршрута и alert-engine. */
export function parseBgpSessions(server: ServerRow, raw: RosBgpSession[]): BgpSessionRead[] {
  return raw.map((s, idx) => {
    const remoteAs = parseInt(s["remote.as"] ?? "0") || 0
    const localAs = parseInt(s["local.as"] ?? "0") || 0
    const type: "eBGP" | "iBGP" = localAs > 0 && localAs === remoteAs ? "iBGP" : "eBGP"

    const localCaps = parseCapabilities(s["local.capabilities"])
    const remoteCaps = parseCapabilities(s["remote.capabilities"])
    const legacyCaps: string[] = []
    if (s["4-octet-as-capability"] === "true") legacyCaps.push("4-byte-AS")
    if (s["as4-capability"] === "true") legacyCaps.push("4-byte-AS")
    if (s["refresh-capability"] === "true") legacyCaps.push("Route Refresh")
    if (s["add-path-capability"] === "true") legacyCaps.push("ADD-PATH")
    if (s["graceful-restart-capability"] === "true") legacyCaps.push("Graceful Restart")
    if (s["extended-message-capability"] === "true") legacyCaps.push("Extended Messages")
    const caps = [...new Set([...localCaps, ...remoteCaps, ...legacyCaps])]

    const holdTime = parseDuration(s["hold-time"]) || parseInt(s["active-holdtime"] ?? "0") || 90

    const keepalive = parseDuration(s["keepalive-time"]) || 30

    const inputMessages =
      parseInt(s["remote.messages"] ?? s["total-messages-received"] ?? "0") || 0
    const outputMessages = parseInt(s["local.messages"] ?? s["total-messages-sent"] ?? "0") || 0

    const peerIp = (s["remote.address"] ?? "").replace(/\/\d+$/, "")

    return {
      id: s[".id"] ?? String(idx),
      serverId: server.id,
      serverName: server.name || server.host,
      serverSite: server.site,
      serverCountry: server.country,
      name: s["name"] ?? peerIp,
      peerIp,
      remoteAs,
      localAs,
      localId: s["local.id"] ?? "",
      remoteId: s["remote.id"] ?? "",
      state: detectState(s),
      type,
      uptime: s["uptime"] || null,
      holdTime,
      keepalive,
      prefixesRx: parseInt(s["prefix-count"] ?? s["total-updates-received"] ?? "0") || 0,
      prefixesTx: parseInt(s["total-updates-sent"] ?? "0") || 0,
      inputMessages,
      outputMessages,
      capabilities: caps,
      lastError: s["last-notification"] || null,
    }
  })
}
