package cn.sikey.mcdisk.util;

import jakarta.servlet.http.HttpServletRequest;
import lombok.experimental.UtilityClass;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @Author: qin
 * @Date: 2025/3/31
 * @Description: ip
 */
@UtilityClass
public class JakartaServletUtil {
    // 预编译正则表达式，用于验证IPv4和IPv6地址
    private static final Pattern IPV4_PATTERN = Pattern.compile("^((25[0-5]|2[0-4][0-9]|?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|?[0-9][0-9]?)$");
    private static final Pattern IPV6_PATTERN = Pattern.compile("^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");

    /**
     * 获取客户端真实IP（支持反向代理场景）
     *
     * @param request HttpServletRequest对象
     * @return 客户端IP地址
     */
    public static String getClientIP(HttpServletRequest request) {
        // 1. 检查反向代理头部
        String ip = getHeaderValue(request, "X-Forwarded-For");
        if (isValidIP(ip)) {
            // 处理多个IP的情况（如 X-Forwarded-For: client, proxy1, proxy2）
            List<String> ips = splitIPs(ip);
            for (String candidateIp : ips) {
                if (isPublicIP(candidateIp)) {
                    return candidateIp;
                }
            }
            return ips.get(0);
        }

        // 2. 检查X-Real-IP
        ip = getHeaderValue(request, "X-Real-IP");
        if (isValidIP(ip)) {
            return ip;
        }

        // 3. 直接获取远程地址
        return request.getRemoteAddr();
    }

    // ---------------------- 工具方法 ----------------------

    /**
     * 获取并验证HTTP头部的值
     */
    private static String getHeaderValue(HttpServletRequest request, String headerName) {
        String value = request.getHeader(headerName);
        return (value != null && !value.isEmpty()) ? value.trim() : null;
    }

    /**
     * 验证IP地址格式
     */
    private static boolean isValidIP(String ip) {
        if (ip == null || ip.isEmpty()) return false;
        return IPV4_PATTERN.matcher(ip).matches() || IPV6_PATTERN.matcher(ip).matches();
    }

    /**
     * 分割多个IP（按逗号分隔）
     */
    private static List<String> splitIPs(String ips) {
        if (ips == null) return Collections.emptyList();
        return Arrays.stream(ips.split(",")).map(String::trim).filter(ip -> !ip.isEmpty()).toList();
    }

    /**
     * 判断是否为公网IP
     */
    private static boolean isPublicIP(String ip) {
        if (ip.startsWith("10.") || ip.startsWith("192.168.") || ip.startsWith("172.16.") || ip.startsWith("169.254.") || ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) {
            return false;
        }
        return true;
    }
}
