package com.chushang.common.core.util;//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.net.Ipv4Util;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.system.OsInfo;
import cn.hutool.system.SystemUtil;
import com.alibaba.fastjson2.JSON;
import org.lionsoul.ip2region.xdb.Searcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class IPUtils {
    private static final Logger log = LoggerFactory.getLogger(IPUtils.class);

    /**
     * 文件地址
     */
    private static final String DB_PATE = "ip2region.xdb";
    /**
     * 查询对象
     */
    private static final Searcher SEARCHER;

    static {
        // 创建一个完全基于内存的查询对象
        try {
            SEARCHER = Searcher.newWithBuffer(ResourceUtil.readBytes(DB_PATE));
            log.info("-------------------- ip2region初始化完成 --------------------");
        } catch (Exception e) {
            log.error("ip2region.xdb初始化失败,地址:[{}]", DB_PATE, e);
            throw new RuntimeException();
        }
    }


    public IPUtils() {
    }


    /**
     * <h2>获取ip地址详细信息</h2>
     *
     * @param ip ip地址
     * @return ip所在城市
     * @author 单傲
     * @date 2023/1/12 14:02
     */
    public static String getLocalCityInfo(String ip) {
        try {
            if (!ip.contains(":")) {
                return NetUtil.isInnerIP(ip) ? "内网IP" : SEARCHER.search(ip).replace("|", "-").replace("-0", StrUtil.EMPTY);
            } else {
                return "未知IP";
            }
        } catch (Exception e) {
            log.error("ip地址解析失败，【{}】", ip, e);
        }
        return null;
    }

    /**
     * <h2>获取ip地址详细信息</h2>
     *
     * @return ip所在城市
     * @author 单傲
     * @date 2023/1/12 14:02
     */
    public static String getLocalCityInfo() {
        return getLocalCityInfo(clientIp(getRequest()));
    }


    /**
     * <h2>获取ip地址详细信息</h2>
     *
     * @return ip所在城市
     * @author 单傲
     * @date 2023/1/12 14:02
     */
    public static String getLocalCityInfo(HttpServletRequest request) {
        return getLocalCityInfo(clientIp(request));
    }

    /**
     * <h2>获取浏览器类型</h2>
     *
     * @param request 请求
     * @return 类型
     * @author 单傲
     * @date 2023/1/12 14:02
     */
    public static String getBrowser(HttpServletRequest request) {
        if (ObjectUtil.isEmpty(request) && StrUtil.isBlank(request.getHeader("User-Agent"))) {
            return StrUtil.EMPTY;
        }
        UserAgent parse = UserAgentUtil.parse(request.getHeader("User-Agent"));
        return parse.isMobile() ? parse.getOs().toString() : parse.getBrowser().toString();
    }

    public static String osName(){
        UserAgent parse = UserAgentUtil.parse(Objects.requireNonNull(getRequest()).getHeader("User-Agent"));
        return parse.getOs().getName();
    }

    /**
     * <h2>是否为app</h2>
     *
     * @author 单傲
     * @date 2023/1/12 14:02
     */
    public static boolean isMobile() {
        UserAgent parse = UserAgentUtil.parse(Objects.requireNonNull(getRequest()).getHeader("User-Agent"));
        return parse.isMobile();
    }

    /**
     * <h2>获取浏览器类型</h2>
     *
     * @return 类型
     * @author 单傲
     * @date 2023/1/12 14:02
     */
    public static String getBrowser() {
        return getBrowser(getRequest());
    }

    /**
     * <h2>Servlet 请求属性</h2>
     *
     * @author 单傲
     * @date 2023/3/15 10:41
     */
    public static ServletRequestAttributes getRequestAttributes() {
        try {
            return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * <h2>获取request</h2>
     *
     * @author 单傲
     * @date 2023/3/15 10:41
     */
    public static HttpServletRequest getRequest() {
        try {
            return getRequestAttributes().getRequest();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * <h2>获取response</h2>
     *
     * @author 单傲
     * @date 2023/3/15 10:41
     */
    public static HttpServletResponse getResponse() {
        try {
            return getRequestAttributes().getResponse();
        } catch (Exception e) {
            return null;
        }
    }

    public static String clientIp(HttpServletRequest request) {
        String realIps = clientIps(request);
        return realIps.contains(",") ? realIps.split(",")[0] : realIps;
    }

    public static String clientIps(HttpServletRequest request)
    {
        String ip = request.getHeader("X-Forwarded-For");
        log.debug("X-Forwarded-For ==>" + ip);
        if (checkIp(ip)) {
            ip = request.getHeader("X-Real-IP");
            log.debug("X-Real-IP ==>" + ip);
        }

        if (checkIp(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
            log.debug("Proxy-Client-IP ==>" + ip);
        }

        if (checkIp(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
            log.debug("WL-Proxy-Client-IP ==>" + ip);
        }

        if (checkIp(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
            log.debug("HTTP_CLIENT_IP ==>" + ip);
        }

        if (checkIp(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            log.debug("HTTP_X_FORWARDED_FOR ==>" + ip);
        }

        if (checkIp(ip)) {
            ip = request.getRemoteAddr();
            log.debug("request.getRemoteAddr() ==>" + ip);
        }

        log.info("RealRemoteIP ==>" + ip);
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    public static String clientIp(ServerHttpRequest request)
    {
         String realIps = clientIps(request);
        return realIps.contains(",") ? realIps.split(",")[0] : realIps;
    }

    public static String clientIps(ServerHttpRequest request)
    {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("X-Forwarded-For");
        // 获取请求主机IP地址,如果通过代理进来，则透过防火墙获取真实IP地址
        log.debug("X-Forwarded-For ==>" + ip);
        if (checkIp(ip)) {
            ip = headers.getFirst("X-Real-IP");
            log.debug("X-Real-IP ==>" + ip);
        }

        if (checkIp(ip)) {
            ip =  headers.getFirst("Proxy-Client-IP");
            log.debug("Proxy-Client-IP ==>" + ip);
        }

        if (checkIp(ip)) {
            ip =  headers.getFirst("WL-Proxy-Client-IP");
            log.debug("WL-Proxy-Client-IP ==>" + ip);
        }

        if (checkIp(ip)) {
            ip =  headers.getFirst("HTTP_CLIENT_IP");
            log.debug("HTTP_CLIENT_IP ==>" + ip);
        }

        if (checkIp(ip)) {
            ip =  headers.getFirst("HTTP_X_FORWARDED_FOR");
            log.debug("HTTP_X_FORWARDED_FOR ==>" + ip);
        }

        if (checkIp(ip)) {
            ip =  Objects.requireNonNull(request.getRemoteAddress()).getAddress().getHostAddress();
            log.debug("request.getRemoteAddr() ==>" + ip);
        }

        log.info("RealRemoteIP ==>" + ip);
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    private static boolean checkIp(String ip) {
        return null == ip || ip.trim().isEmpty() || "unknown".equalsIgnoreCase(ip);
    }

    public static boolean isInvalid(String ip) {
        if (null != ip && !ip.trim().isEmpty() && !"unknown".equalsIgnoreCase(ip) && ip.length() >= 7 && ip.length() <= 15) {
            String rexp = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
            Pattern pat = Pattern.compile(rexp);
            Matcher mat = pat.matcher(ip);
            return mat.find();
        } else {
            return false;
        }
    }

    public static String getLocalHost() {
        try {
            return getLocalAddress().getHostAddress();
        } catch (Exception var1) {
            return "127.0.0.1";
        }
    }

    public static boolean internalIp(String ip) {
        byte[] addr = textToNumericFormatV4(ip);
        return internalIp(addr) || "127.0.0.1".equals(ip);
    }

    private static boolean internalIp(byte[] addr) {
        byte b0 = addr[0];
        byte b1 = addr[1];
        boolean SECTION_1 = true;
        boolean SECTION_2 = true;
        boolean SECTION_3 = true;
        boolean SECTION_4 = true;
        boolean SECTION_5 = true;
        boolean SECTION_6 = true;
        switch (b0) {
            case -84:
                if (b1 >= 16 && b1 <= 31) {
                    return true;
                }
            case -64:
                switch (b1) {
                    case -88:
                        return true;
                }
            default:
                return false;
            case 10:
                return true;
        }
    }

    public static byte[] textToNumericFormatV4(String text) {
        if (text.length() == 0) {
            return null;
        } else {
            byte[] bytes = new byte[4];
            String[] elements = text.split("\\.", -1);

            try {
                long l;
                int i;
                switch (elements.length) {
                    case 1:
                        l = Long.parseLong(elements[0]);
                        if (l < 0L || l > 4294967295L) {
                            return null;
                        }

                        bytes[0] = (byte)((int)(l >> 24 & 255L));
                        bytes[1] = (byte)((int)((l & 16777215L) >> 16 & 255L));
                        bytes[2] = (byte)((int)((l & 65535L) >> 8 & 255L));
                        bytes[3] = (byte)((int)(l & 255L));
                        break;
                    case 2:
                        l = (long)Integer.parseInt(elements[0]);
                        if (l >= 0L && l <= 255L) {
                            bytes[0] = (byte)((int)(l & 255L));
                            l = (long)Integer.parseInt(elements[1]);
                            if (l < 0L || l > 16777215L) {
                                return null;
                            }

                            bytes[1] = (byte)((int)(l >> 16 & 255L));
                            bytes[2] = (byte)((int)((l & 65535L) >> 8 & 255L));
                            bytes[3] = (byte)((int)(l & 255L));
                            break;
                        }

                        return null;
                    case 3:
                        for(i = 0; i < 2; ++i) {
                            l = (long)Integer.parseInt(elements[i]);
                            if (l < 0L || l > 255L) {
                                return null;
                            }

                            bytes[i] = (byte)((int)(l & 255L));
                        }

                        l = (long)Integer.parseInt(elements[2]);
                        if (l < 0L || l > 65535L) {
                            return null;
                        }

                        bytes[2] = (byte)((int)(l >> 8 & 255L));
                        bytes[3] = (byte)((int)(l & 255L));
                        break;
                    case 4:
                        for(i = 0; i < 4; ++i) {
                            l = (long)Integer.parseInt(elements[i]);
                            if (l < 0L || l > 255L) {
                                return null;
                            }

                            bytes[i] = (byte)((int)(l & 255L));
                        }

                        return bytes;
                    default:
                        return null;
                }

                return bytes;
            } catch (NumberFormatException var6) {
                return null;
            }
        }
    }

    public static String getLocalHostName() {
        try {
            return getLocalAddress().getHostName();
        } catch (Exception var1) {
            return "未知";
        }
    }

    public static InetAddress getLocalAddress() {
        InetAddress candidateAddress = null;

        try {
            Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();

            label60:
            while(true) {
                while(true) {
                    if (!ifaces.hasMoreElements()) {
                        break label60;
                    }

                    NetworkInterface iface = (NetworkInterface)ifaces.nextElement();
                    if (iface.isLoopback()) {
                        log.trace("NetworkInterface is Loopback:{} discard continue", JSON.toJSONString(iface));
                    } else if (iface.isVirtual()) {
                        log.trace("NetworkInterface is Virtual:{} discard continue", JSON.toJSONString(iface));
                    } else if (!iface.isUp()) {
                        log.trace("NetworkInterface is shutdown:{} discard continue", JSON.toJSONString(iface));
                    } else {
                        log.trace("NetworkInterface is normal:{} continue", JSON.toJSONString(iface));
                        Enumeration<InetAddress> inetAddrs = iface.getInetAddresses();

                        while(inetAddrs.hasMoreElements()) {
                            InetAddress inetAddr = (InetAddress)inetAddrs.nextElement();
                            if (inetAddr.isLoopbackAddress()) {
                                log.trace("InetAddress is Loopback:{} discard continue", JSON.toJSONString(inetAddr));
                            } else {
                                if (inetAddr.isSiteLocalAddress()) {
                                    candidateAddress = inetAddr;
                                    break;
                                }

                                log.trace("Don't want to InetAddress:{}", JSON.toJSONString(inetAddr));
                                if (candidateAddress == null) {
                                    candidateAddress = inetAddr;
                                }
                            }
                        }

                        if (candidateAddress != null) {
                            break label60;
                        }
                    }
                }
            }

            if (candidateAddress == null) {
                InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
                if (jdkSuppliedAddress != null) {
                    candidateAddress = jdkSuppliedAddress;
                    log.warn("not found non-loopback InetAddress,use default scheme(InetAddress.getLocalHost()):{}", jdkSuppliedAddress);
                } else {
                    log.warn("use default scheme(InetAddress.getLocalHost()) is null");
                }
            }
        } catch (Exception var5) {
            Exception e = var5;
            log.error("Exception:{}", e);
        }

        log.debug("IP:{},HostName:{}", candidateAddress.getHostAddress(), candidateAddress.getHostName());
        return candidateAddress;
    }
}
