package common.utils;

import com.jfinal.core.Controller;
import com.jfinal.kit.StrKit;

import javax.servlet.http.HttpServletRequest;

public class IpAddressUtil {
    /**
     * 在 Controller 中获取请求方的公网 IP 地址
     * 考虑了多层代理（CDN, 负载均衡器, 反向代理等）的情况
     *
     * @param controller JFinal的Controller实例
     * @return 客户端公网IP地址，如果获取失败则返回 null 或空字符串
     */
    public static String getClientIpAddress(Controller controller) {
        return getClientIpAddress(controller.getRequest());
    }

    /**
     * 获取请求方的公网 IP 地址
     * 考虑了多层代理（CDN, 负载均衡器, 反向代理等）的情况
     *
     * @param request HttpServletRequest 请求对象
     * @return 客户端公网IP地址，如果获取失败则返回 null 或空字符串
     */
    public static String getClientIpAddress(HttpServletRequest request) {
        if (request == null) {
            return null;
        }

        // 顺序检查各种可能的代理Header
        String ip = request.getHeader("X-Forwarded-For");
        if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // X-Forwarded-For 可能包含多个 IP 地址，用逗号分隔，第一个通常是真实客户端IP
            int commaOffset = ip.indexOf(',');
            if (commaOffset > 0) {
                ip = ip.substring(0, commaOffset);
            }
            return ip.trim();
        }

        ip = request.getHeader("Proxy-Client-IP");
        if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip.trim();
        }

        ip = request.getHeader("WL-Proxy-Client-IP");
        if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip.trim();
        }

        ip = request.getHeader("HTTP_CLIENT_IP");
        if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip.trim();
        }

        ip = request.getHeader("HTTP_X_FORWARDED_FOR"); // 有些代理会使用此Header
        if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            int commaOffset = ip.indexOf(',');
            if (commaOffset > 0) {
                ip = ip.substring(0, commaOffset);
            }
            return ip.trim();
        }

        // 最终回退到 Servlet API 的默认获取方式
        // 这个通常是直接连接到你应用服务器的代理服务器的IP，而不是客户端真实IP
        ip = request.getRemoteAddr();
        return ip;
    }

    // 考虑到可能会有 IPv6 地址，但通常情况下我们关心 IPv4。
    // 如果需要专门处理 IPv6，可以在匹配 IP 地址时进行正则判断。
}
