package com.ycwl.basic.utils;

import org.apache.commons.lang3.StringUtils;

/**
 * IPv4 CIDR 匹配工具
 */
public final class Ipv4CidrMatcher {

    private Ipv4CidrMatcher() {
    }

    /**
     * 判断 IPv4 是否命中 CIDR（如：100.64.0.0/24）。
     * - 若 cidr 不包含 '/'，则按“完全相等”处理。
     * - 仅支持 IPv4；IPv6 返回 false。
     */
    public static boolean matches(String ip, String cidr) {
        if (StringUtils.isBlank(ip) || StringUtils.isBlank(cidr)) {
            return false;
        }

        String cleanedIp = ip.trim();
        if (cleanedIp.contains(":")) {
            return false;
        }

        String cleanedCidr = cidr.trim();
        int slashIndex = cleanedCidr.indexOf('/');
        if (slashIndex < 0) {
            return cleanedIp.equals(cleanedCidr);
        }

        String networkPart = cleanedCidr.substring(0, slashIndex).trim();
        String prefixPart = cleanedCidr.substring(slashIndex + 1).trim();

        Integer ipInt = parseIpv4ToInt(cleanedIp);
        Integer networkInt = parseIpv4ToInt(networkPart);
        if (ipInt == null || networkInt == null) {
            return false;
        }

        Integer prefixLength = parsePrefixLength(prefixPart);
        if (prefixLength == null) {
            return false;
        }

        int mask = prefixLength == 0 ? 0 : (-1 << (32 - prefixLength));
        return (ipInt & mask) == (networkInt & mask);
    }

    private static Integer parsePrefixLength(String prefixPart) {
        try {
            int prefixLength = Integer.parseInt(prefixPart);
            if (prefixLength < 0 || prefixLength > 32) {
                return null;
            }
            return prefixLength;
        } catch (Exception e) {
            return null;
        }
    }

    private static Integer parseIpv4ToInt(String ip) {
        if (StringUtils.isBlank(ip)) {
            return null;
        }
        String[] parts = ip.trim().split("\\.");
        if (parts.length != 4) {
            return null;
        }

        long result = 0;
        for (String part : parts) {
            int value;
            try {
                value = Integer.parseInt(part);
            } catch (Exception e) {
                return null;
            }

            if (value < 0 || value > 255) {
                return null;
            }

            result = (result << 8) | value;
        }

        return (int) result;
    }
}
