/* (C) 2024 YiRing, Inc. */
package com.yiring.common.util;

import jakarta.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.LongByteArray;
import org.lionsoul.ip2region.xdb.Searcher;
import org.lionsoul.ip2region.xdb.Version;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.FileCopyUtils;

/**
 * @author Jim
 */
@SuppressWarnings("unused")
@Slf4j
@UtilityClass
public class IpUtil {

    /**
     * 代理 IP 请求头
     */
    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",
        "X-Real-IP",
    };

    private static Searcher searcher;

    static {
        try {
            ClassPathResource resource = new ClassPathResource("ipdb/ip2region.xdb");
            InputStream is = resource.getInputStream();
            byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
            searcher = Searcher.newWithBuffer(Version.IPv4, new LongByteArray(bytes));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /***
     * 获取客户端ip地址(可以穿透代理)
     *
     * @param request HttpServletRequest
     * @return IP
     */
    public String getClientIp(HttpServletRequest request) {
        for (String header : HEADERS_TO_TRY) {
            String ip = request.getHeader(header);
            if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
                return ip;
            }
        }

        return request.getRemoteAddr();
    }

    /**
     * 判断是否为合法 IP
     */
    public static boolean checkIp(String ipAddress) {
        String ip = "([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 pattern = Pattern.compile(ip);
        Matcher matcher = pattern.matcher(ipAddress);
        return matcher.matches();
    }

    /**
     * 获取 ip 属地
     *
     * @param ip ip
     * @return ip 属地
     */
    public static String getIpRegion(String ip) {
        if (checkIp(ip)) {
            try {
                // searchIpInfo 的数据格式： 国家|区域|省份|城市|ISP
                String searchIpInfo = searcher.search(ip);
                String[] splitIpInfo = searchIpInfo.split("\\|");
                if (splitIpInfo.length > 0) {
                    if ("中国".equals(splitIpInfo[0])) {
                        // 国内属地返回城市
                        return splitIpInfo[3];
                    } else if ("0".equals(splitIpInfo[0])) {
                        if ("内网IP".equals(splitIpInfo[4])) {
                            // 内网 IP
                            return splitIpInfo[4];
                        }
                    } else {
                        // 国外属地返回国家
                        return splitIpInfo[0];
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }

            return "";
        } else {
            throw new IllegalArgumentException("Illegal IP address");
        }
    }
}
