import { eq } from "drizzle-orm"
import { db } from "../db/index.js"
import { servers } from "../db/schema.js"
import { MikrotikClient } from "./mikrotik.js"
import {
  rememberServerIfaces,
  shouldRefreshIfaces,
  markIfaceRefreshAttempt,
  type RosIfaceIndexRow,
} from "./traffic-flow-ifindex.js"

export {
  ifaceCacheFresh,
  ifaceCacheHas,
  rememberServerIfaces,
  resetIfaceCacheForTests,
  resolveIfaceName,
  rosIdToIfIndex,
  shouldRefreshIfaces,
  markIfaceRefreshAttempt,
} from "./traffic-flow-ifindex.js"

const inflight = new Set<number>()
let refreshIfacesImpl: (serverId: number, force?: boolean) => Promise<void> = refreshServerIfacesInner

async function refreshServerIfacesInner(serverId: number, force = false): Promise<void> {
  if (inflight.has(serverId)) return
  if (!force && !shouldRefreshIfaces(serverId)) return
  inflight.add(serverId)
  try {
    const row = db.select().from(servers).where(eq(servers.id, serverId)).limit(1).all()[0]
    if (!row) return
    const client = MikrotikClient.fromServer(row)
    const ifaces = await client.get<RosIfaceIndexRow[]>("/interface")
    rememberServerIfaces(serverId, Array.isArray(ifaces) ? ifaces : [])
  } catch {
    /* keep previous cache */
  } finally {
    markIfaceRefreshAttempt(serverId)
    inflight.delete(serverId)
  }
}

export async function refreshServerIfaces(serverId: number, force = false): Promise<void> {
  return refreshIfacesImpl(serverId, force)
}

export function maybeRefreshIfaces(serverId: number): boolean {
  if (!shouldRefreshIfaces(serverId)) return false
  void refreshIfacesImpl(serverId)
  return true
}

export function setRefreshIfacesForTests(fn: typeof refreshServerIfacesInner | null): void {
  refreshIfacesImpl = fn ?? refreshServerIfacesInner
}
