import { promises as dns } from "node:dns"
import type { FastifyPluginAsyncZod } from "@fastify/type-provider-zod"
import { z } from "zod"

const IPV4 =
  /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/

function isIpv4(s: string): boolean {
  return IPV4.test(s.trim())
}

/** Кэш DNS на процесс (GRE outer меняется редко). */
const resolveCache = new Map<string, { ip: string | null; expires: number }>()
const TTL_MS = 5 * 60 * 1000

async function resolveHostToIpv4(hostname: string): Promise<string | null> {
  const key = hostname.trim().toLowerCase()
  if (!key || isIpv4(key)) return isIpv4(key) ? key.trim() : null

  const hit = resolveCache.get(key)
  if (hit && hit.expires > Date.now()) return hit.ip

  try {
    const { address } = await dns.lookup(key, { family: 4 })
    const ip = isIpv4(address) ? address : null
    resolveCache.set(key, { ip, expires: Date.now() + TTL_MS })
    return ip
  } catch {
    resolveCache.set(key, { ip: null, expires: Date.now() + TTL_MS })
    return null
  }
}

const ResolveHostsBodySchema = z.object({
  hosts: z.array(z.string().max(253)).max(32),
})

const networkRoutes: FastifyPluginAsyncZod = async (app) => {
  /**
   * Резолв FQDN из GRE outer (remote-address / local-address) в IPv4 для сопоставления с WAN в каталоге.
   */
  app.post("/network/resolve-hosts", async (req, reply) => {
    const parsed = ResolveHostsBodySchema.safeParse(req.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: "Invalid body", details: parsed.error.flatten() })
    }

    const seen = new Set<string>()
    const unique: string[] = []
    for (const h of parsed.data.hosts) {
      const k = h.trim().toLowerCase()
      if (!k || seen.has(k)) continue
      seen.add(k)
      unique.push(h.trim())
    }

    const results: Record<string, string | null> = {}
    for (const host of unique) {
      const key = host.toLowerCase()
      results[key] = await resolveHostToIpv4(host)
    }

    return reply.send({ results })
  })
}

export default networkRoutes
