package com.ytpm.util;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author lih
 * @date 2025/9/4
 */
public class IPUtil {

    public static String getClientIp(HttpServletRequest request) {
        String xfHeader = request.getHeader("X-Forwarded-For");
        if (xfHeader == null) {
            return request.getRemoteAddr();
        }
        return xfHeader.split(",")[0]; // 可能会有多个IP，这里取第一个逗号前的IP
    }


    // 严格的CIDR正则表达式（支持 x.x.x.x/x 格式）
    private static final Pattern CIDR_PATTERN = Pattern.compile(
            "^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)/([0-9]|[1-2]\\d|3[0-2])$"
    );

    // 严格的IPv4正则表达式（禁止前导零）
    private static final Pattern IPV4_PATTERN = Pattern.compile(
            "^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$"
    );

    /**
     * 校验IP是否在白名单中（支持单个IP和CIDR网段）
     * @param ip 待校验的IP地址
     * @param whitelist 白名单列表，支持IPv4和CIDR格式
     * @return 是否在白名单中
     */
    public static boolean isIpInWhitelist(String ip, List<String> whitelist) {
        // 参数校验
        if (ip == null || ip.trim().isEmpty() || whitelist == null || whitelist.isEmpty()) {
            return false;
        }

        ip = ip.trim();
        // 预校验IP格式
        if (!IPV4_PATTERN.matcher(ip).matches()) {
            return false;
        }

        // 遍历白名单进行匹配
        for (String item : whitelist) {
            if (item == null) {
                continue;
            }

            String trimmedItem = item.trim();
            if (trimmedItem.isEmpty()) {
                continue;
            }

            // 优先检查精确IP匹配
            if (IPV4_PATTERN.matcher(trimmedItem).matches()) {
                if (ip.equals(trimmedItem)) {
                    return true;
                }
                continue;
            }

            // 检查CIDR网段匹配
            if (CIDR_PATTERN.matcher(trimmedItem).matches()) {
                try {
                    if (isIpInCidr(ip, trimmedItem)) {
                        return true;
                    }
                } catch (IllegalArgumentException e) {
                    // 记录日志或忽略无效的CIDR条目
                    continue;
                }
            }
        }
        return false;
    }

    /**
     * 校验IP是否在CIDR网段内
     * 例：IP=192.168.1.100，CIDR=192.168.1.0/24 → 返回 true
     * @param ip IPv4地址
     * @param cidr CIDR网段格式
     * @return 是否在网段内
     * @throws IllegalArgumentException 参数格式无效时抛出
     */
    public static boolean isIpInCidr(String ip, String cidr) {
        if (ip == null || cidr == null) {
            throw new IllegalArgumentException("IP和CIDR不能为null");
        }

        // 使用预编译的正则进行格式校验
        if (!CIDR_PATTERN.matcher(cidr).matches()) {
            throw new IllegalArgumentException("无效的CIDR网段格式：" + cidr);
        }

        if (!IPV4_PATTERN.matcher(ip).matches()) {
            throw new IllegalArgumentException("无效的IPv4地址：" + ip);
        }

        String[] cidrParts = cidr.split("/");
        String networkIp = cidrParts[0];
        int prefixLength = Integer.parseInt(cidrParts[1]);

        // 校验掩码长度范围
        if (prefixLength < 0 || prefixLength > 32) {
            throw new IllegalArgumentException("CIDR掩码长度必须在0-32之间：" + prefixLength);
        }

        // 计算子网掩码（处理32位边界情况）
        long subnetMask = prefixLength == 0 ? 0 : (0xFFFFFFFFL << (32 - prefixLength));
        // 计算网络地址
        long ipLong = ipToLong(ip);
        long networkIpLong = ipToLong(networkIp);

        // 比较网络地址
        return (ipLong & subnetMask) == (networkIpLong & subnetMask);
    }

    /**
     * IPv4地址转长整型
     * 例：192.168.1.1 → 3232235777
     * @param ip IPv4地址字符串
     * @return 对应的长整型数值
     * @throws IllegalArgumentException IP格式无效时抛出
     */
    public static long ipToLong(String ip) {
        if (ip == null) {
            throw new IllegalArgumentException("IP地址不能为null");
        }

        if (!IPV4_PATTERN.matcher(ip).matches()) {
            throw new IllegalArgumentException("无效的IPv4地址：" + ip);
        }

        String[] parts = ip.split("\\.");
        long result = 0;
        for (int i = 0; i < 4; i++) {
            int segment = Integer.parseInt(parts[i]);
            if (segment < 0 || segment > 255) {
                throw new IllegalArgumentException("IP地址段超出范围：" + segment);
            }
            result |= (segment & 0xFFL) << (8 * (3 - i));
        }
        return result;
    }
}
