package com.crm.rely.backend.util;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.*;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

public class GetIpAndMac {
    private static final String[] HEADERS_TO_TRY = {
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_X_FORWARDED_FOR",
            "HTTP_X_FORWARDED",
            "HTTP_X_CLUSTER_CLIENT_IP",
            "HTTP_CLIENT_IP",
            "HTTP_FORWARDED_FOR",
            "HTTP_FORWARDED",
            "HTTP_VIA",
            "REMOTE_ADDR"
    };

    private static final List<IPRange> LOCAL_RANGES = Arrays.asList(
            IPRange.parse("10.0.0.0/8"),
            IPRange.parse("172.16.0.0/12"),
            IPRange.parse("192.168.0.0/16"),
            IPRange.parse("127.0.0.1/32"),
            IPRange.parse("::1/128")
    );


    /**
     * 获取IP地址
     *
     * @param request
     * @return
     */
    public static String getIp(HttpServletRequest request) {
        String ip = null;
        for (String header : HEADERS_TO_TRY) {
            ip = request.getHeader(header);
            if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
                break;
            }
        }

        // 如果请求来自Cloudflare代理，确认客户端真实IP地址
        if (ip != null && !ip.isEmpty() && request.getHeader("CF-Connecting-IP") != null) {
            String cfConnectingIP = request.getHeader("CF-Connecting-IP");
            if (!cfConnectingIP.isEmpty() && !"unknown".equalsIgnoreCase(cfConnectingIP) && isIPAddress(cfConnectingIP) && !isLocalAddress(cfConnectingIP)) {
                ip = cfConnectingIP;
            }
        }

        // 如果请求来自Nginx代理，确认客户端真实IP地址
        if (ip != null && !ip.isEmpty() && request.getHeader("X-Real-IP") != null) {
            String xRealIP = request.getHeader("X-Real-IP");
            if (!xRealIP.isEmpty() && !"unknown".equalsIgnoreCase(xRealIP) && isIPAddress(xRealIP) && !isLocalAddress(xRealIP)) {
                ip = xRealIP;
            }
        }

        // 如果HTTP头中存在多个IP地址，选择第一个非本地地址作为客户端真实IP地址
        if (ip != null && ip.contains(",")) {
            String[] ips = ip.split(",");
            if (ips.length > 0) {
                ip = ips[0];
            }
            for (String i : ips) {
                i = i.trim();
                if (!i.isEmpty() && !"unknown".equalsIgnoreCase(i) && isIPAddress(i) && !isLocalAddress(i)) {
                    ip = i;
                    break;
                }
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (!IPRange.isIPv4Address(ip)) {
            ip = getIpv4(ip);
        }

        return ip;
    }

    private static boolean isIPAddress(String ipAddress) {
//        return IPRange.isIPv4Address(ipAddress) || IPRange.isIPv6Address(ipAddress);
        return IPRange.isIPv4Address(ipAddress);
    }

    private static boolean isLocalAddress(String ipAddress) {
        for (IPRange range : LOCAL_RANGES) {
            if (range.contains(ipAddress)) {
                return true;
            }
        }
        return false;
    }


    /**
     * unicode 转换成 中文
     */
    private static String decodeUnicode(String theString) {
        char aChar;
        int len = theString.length();
        StringBuffer outBuffer = new StringBuffer(len);
        for (int x = 0; x < len; ) {
            aChar = theString.charAt(x++);
            if (aChar == '\\') {
                aChar = theString.charAt(x++);
                if (aChar == 'u') {
                    int value = 0;
                    for (int i = 0; i < 4; i++) {
                        aChar = theString.charAt(x++);
                        switch (aChar) {
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                value = (value << 4) + aChar - '0';
                                break;
                            case 'a':
                            case 'b':
                            case 'c':
                            case 'd':
                            case 'e':
                            case 'f':
                                value = (value << 4) + 10 + aChar - 'a';
                                break;
                            case 'A':
                            case 'B':
                            case 'C':
                            case 'D':
                            case 'E':
                            case 'F':
                                value = (value << 4) + 10 + aChar - 'A';
                                break;
                            default:
                                throw new IllegalArgumentException(
                                        "Malformed      encoding.");
                        }
                    }
                    outBuffer.append((char) value);
                } else {
                    if (aChar == 't') {
                        aChar = '\t';
                    } else if (aChar == 'r') {
                        aChar = '\r';
                    } else if (aChar == 'n') {
                        aChar = '\n';
                    } else if (aChar == 'f') {
                        aChar = '\f';
                    }
                    outBuffer.append(aChar);
                }
            } else {
                outBuffer.append(aChar);
            }
        }
        return outBuffer.toString();
    }

    //获取ip
    public static String getLocalIP() {
        String localIP = "127.0.0.1";
        try {
            OK:
            for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements(); ) {
                NetworkInterface networkInterface = interfaces.nextElement();
                if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) {
                    continue;
                }
                Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress address = addresses.nextElement();
                    if (address instanceof Inet4Address) {
                        localIP = address.getHostAddress();
                        break OK;
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return localIP;
    }

    public static String getIpv4(String ipv6) {
        String ipv4 = null;
        try {
            InetAddress inet6 = InetAddress.getByName(ipv6);
            byte[] bytes = inet6.getAddress();
            if (bytes.length == 16) {
                byte[] b = new byte[4];
                System.arraycopy(bytes, 12, b, 0, 4);
                InetAddress inet4 = InetAddress.getByAddress(b);
                ipv4 = inet4.getHostAddress();
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return ipv4;
    }

    //通过request获取ip
    public static String getIp() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServerName();
    }

    //通过request获取端口
    public static String getLocalPort() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServerPort() + "";
    }

    public static String getIpAndPort() {
        return getLocalIP() + ":" + getLocalPort();
    }

    public static String getClientIp(HttpServletRequest req) {
        return req.getHeader("CLIENT");
    }


    public static void main(String[] args) {
//        String ip = "240e:304:2c80:e037:962:a9aa:f1ec:62d";
        String ip = "2408:8456:f11c:883d::1";
        try {
            if (!IPRange.isIPv4Address(ip)) {
                ip = getIpv4(ip);
            }
            System.out.println(ip);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class IPRange {
    private final long start;
    private final long end;

    private IPRange(long start, long end) {
        this.start = start;
        this.end = end;
    }

    public static IPRange parse(String cidr) {
        String[] parts = cidr.split("/");
        String ip = parts[0];
        int prefixLength = Integer.parseInt(parts[1]);
        long start = ipToLong(ip);
        long end = start | ((1L << (32 - prefixLength)) - 1);
        return new IPRange(start, end);
    }

    public boolean contains(String ipAddress) {
        long ip = ipToLong(ipAddress);
        return ip >= start && ip <= end;
    }

    private static long ipToLong(String ipAddress) {
        if (isIPv4Address(ipAddress)) {
            String[] parts = ipAddress.split("\\.");
            return (Long.parseLong(parts[0]) << 24) +
                    (Long.parseLong(parts[1]) << 16) +
                    (Long.parseLong(parts[2]) << 8) +
                    Long.parseLong(parts[3]);
        } else if (isIPv6Address(ipAddress)) {
            String[] parts = ipAddress.split(":");
            long hi = 0;
            long lo = 0;
            boolean inHi = true;
            for (String part : parts) {
                if (part.isEmpty()) {
                    inHi = false;
                    continue;
                }
                long value = Long.parseLong(part, 16);
                if (inHi) {
                    hi = (hi << 16) | value;
                } else {
                    lo = (lo << 16) | value;
                }
            }
            return (hi << 64) | lo;
        } else {
            throw new IllegalArgumentException("Invalid IP address: " + ipAddress);
        }
    }

    protected static boolean isIPv4Address(String ipAddress) {
        return ipAddress.matches("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
                "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
                "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
                "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
    }

    protected static boolean isIPv6Address(String ipAddress) {
        return ipAddress.matches("^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$") ||
                ipAddress.matches("^([0-9a-fA-F]{1,4}:){6}:([0-9a-fA-F]{1,4}:){1,2}[0-9a-fA-F]{1,4}$") ||
                ipAddress.matches("^([0-9a-fA-F]{1,4}:){5}:([0-9a-fA-F]{1,4}:){1,3}[0-9a-fA-F]{1,4}$") ||
                ipAddress.matches("^([0-9a-fA-F]{1,4}:){4}:([0-9a-fA-F]{1,4}:){1,4}[0-9a-fA-F]{1,4}$") ||
                ipAddress.matches("^([0-9a-fA-F]{1,4}:){3}:([0-9a-fA-F]{1,4}:){1,5}[0-9a-fA-F]{1,4}$") ||
                ipAddress.matches("^([0-9a-fA-F]{1,4}:){2}:([0-9a-fA-F]{1,4}:){1,6}[0-9a-fA-F]{1,4}$") ||
                ipAddress.matches("^([0-9a-fA-F]{1,4}:){1}:([0-9a-fA-F]{1,4}:){1,7}[0-9a-fA-F]{1,4}$") ||
                ipAddress.matches("^:((:[0-9a-fA-F]{1,4}){1,7}|:)$");
    }
}