package com.ffii.fpsms.modules.monitoring.web

import jakarta.servlet.http.HttpServletRequest

object ClientIpResolver {
    /**
     * Best-effort client IP from proxy headers, then TCP remote address.
     * Skips loopback when a routable address is present; normalizes ::1 for display.
     */
    fun resolve(request: HttpServletRequest): String? {
        val candidates = linkedSetOf<String>()

        fun addHeader(name: String) {
            val raw = request.getHeader(name)?.trim() ?: return
            raw.split(",").forEach { part ->
                val ip = part.trim().take(45)
                if (ip.isNotBlank()) candidates.add(ip)
            }
        }

        addHeader("X-Forwarded-For")
        addHeader("X-Real-IP")
        addHeader("CF-Connecting-IP")
        request.remoteAddr?.trim()?.takeIf { it.isNotBlank() }?.let { candidates.add(it.take(45)) }

        if (candidates.isEmpty()) return null

        val routable = candidates.firstOrNull { !isLoopback(it) }
        if (routable != null) return routable

        return normalizeLoopbackDisplay(candidates.first())
    }

    private fun isLoopback(ip: String): Boolean {
        val n = ip.trim().lowercase()
        if (n == "localhost" || n.startsWith("127.")) return true
        if (n == "::1" || n == "0:0:0:0:0:0:0:1") return true
        // Any all-zero IPv6 address (loopback / unspecified)
        if (n.contains(":") && n.replace(":", "").replace("0", "").isEmpty()) return true
        return false
    }

    /** Loopback = browser on same machine as API (local dev or server console). */
    private fun normalizeLoopbackDisplay(ip: String): String =
        if (isLoopback(ip)) "Server" else ip
}
