package com.pig4cloud.pig.common.core.util.ip;

import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.log4j.Log4j2;
import org.lionsoul.ip2region.xdb.Searcher;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Log4j2
public class IPUtils {

	// 内网IP段正则
	private static final String INTRANET_IP_REGEX = "(10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|" +
			"(172\\.((1[6-9])|(2\\d)|(3[01]))\\.\\d{1,3}\\.\\d{1,3})|" +
			"(192\\.168\\.\\d{1,3}\\.\\d{1,3})|" +
			"(127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})";
	private static final Pattern INTRANET_PATTERN = Pattern.compile(INTRANET_IP_REGEX);

	// IP地址合法性校验正则
	private static final String IP_REGEX = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." +
			"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." +
			"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." +
			"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
	private static final Pattern IP_PATTERN = Pattern.compile(IP_REGEX);

	private static Searcher searcher;

	static {
		initIpSearcher();
	}

	/**
	 * 初始化IP地址索引
	 */
	private static void initIpSearcher() {
		try {
			// 基于内存查询-从资源文件加载xdb数据库
			String dbPath = IPUtils.class.getClassLoader().getResource("ip/ip2region.xdb").getPath();
			byte[] cBuff = Searcher.loadContentFromFile(dbPath);
			searcher = Searcher.newWithBuffer(cBuff);
			log.info("ip2region初始化成功");
		} catch (Exception e) {
			log.error("ip2region初始化失败", e);
			searcher = null;
		}
	}

	/**
	 * 获取IP地址
	 *
	 * @param request request
	 * @return ipAddress
	 */
	public static String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		// 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
		if (ip != null && ip.length() > 15) {
			if (ip.indexOf(",") > 0) {
				ip = ip.substring(0, ip.indexOf(","));
			}
		}
		if ("127.0.0.1".equals(ip)) {
			// 获取本机真正的ip地址
			try {
				ip = InetAddress.getLocalHost().getHostAddress();
			} catch (UnknownHostException e) {
				log.error(e.getMessage(), e);
			}
		}
		return ip;
	}

	/**
	 * 判断是否内网IP
	 * @param ip ip
	 * @return boolean
	 */
	public static boolean isIntranetIp(String ip) {
		if (StrUtil.isBlank(ip)) {
			return false;
		}
		Matcher matcher = INTRANET_PATTERN.matcher(ip);
		return matcher.matches();
	}

	/**
	 * 检查IP是否合法
	 * @param ip ip
	 * @return boolean
	 */

	public static boolean isValidIp(String ip) {
		if (StrUtil.isBlank(ip)) {
			return false;
		}
		Matcher matcher = IP_PATTERN.matcher(ip);
		return matcher.matches();
	}

	/**
	 * 比较两个IP地址大小（将IP转为Long比较）
	 * @return true：endIp > startIp
	 */
	public static boolean isEndIpGreater(String startIp, String endIp) {
		if (!isValidIp(startIp) || !isValidIp(endIp)) {
			return false;
		}
		return ipToLong(startIp) < ipToLong(endIp);
	}

	/**
	 * IP地址转Long（便于比较大小）
	 */
	private static long ipToLong(String ip) {
		String[] parts = ip.split("\\.");
		long result = 0;
		for (int i = 0; i < 4; i++) {
			result |= Long.parseLong(parts[i]) << (24 - i * 8);
		}
		return result;
	}

	/**
	 * 获取IP归属地（国家-省份）
	 * @param ip ip
	 * @return 国家-省份
	 */
	public static String getIpRegion(String ip) {
		// 处理多IP情况，取第一个
		if (StrUtil.isNotBlank(ip) && ip.contains(",")) {
			String[] split = ip.split(",");
			ip = split[0].trim();
		}

		// 检查IP合法性
		if (!isValidIp(ip)) {
			return "未知";
		}

		// 检查是否为内网IP
		if (isIntranetIp(ip)) {
			return "内网";
		}

		// 如果搜索器未初始化成功，返回未知
		if (searcher == null) {
			log.warn("ip2region搜索器未初始化，无法查询IP归属地");
			return "未知";
		}

		try {
			String region = searcher.search(ip);
			if (StrUtil.isNotBlank(region)) {
				List<String> arr = StrUtil.split(region, '|');
				// 确保数组有足够的元素
				if (arr.size() >= 3) {
					String country = "0".equals(arr.get(0)) ? "未知" : arr.get(0);
					String province = "0".equals(arr.get(2)) ? "未知" : arr.get(2);

					// 处理国外省份可能为0的情况
					if ("未知".equals(province) && !"中国".equals(country)) {
						return country;
					}

					return country + "-" + province;
				}
			}
		} catch (Exception e) {
			log.warn("查询IP[{}]归属地出错", ip, e);
		}

		return "未知";
	}

	/**
	 * 获取外网IP
	 * @return ip
	 */
	public static String getPublicIp() {
		String ip = "";
		StringBuilder inputLine = new StringBuilder();
		String read;
		BufferedReader in = null;
		try {
			URL url = new URL("http://ip.chinaz.com");
			HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
			in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8));
			while ((read = in.readLine()) != null) {
				inputLine.append(read).append("\r\n");
			}
		} catch (IOException e) {
			log.error("获取公网IP失败:{}",e.getMessage());
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					log.error("获取公网IP失败:{}",e.getMessage());
				}
			}
		}
		Pattern p = Pattern.compile("<dd class=\"fz24\">(.*?)</dd>");
		Matcher m = p.matcher(inputLine.toString());
		if (m.find()) {
			ip = m.group(1);
		}
		log.info("获取的公网ip为[{}]", ip);
		return ip;
	}

	public static void main(String[] args) {
		// 测试案例
		System.out.println(getIpRegion("39.144.24.215"));   // 中国-北京
		System.out.println(getIpRegion("103.26.94.206"));  // 中国-香港
		System.out.println(getIpRegion("153.35.52.159"));  // 日本-未知
		System.out.println(getIpRegion("8.8.8.8"));        // 美国-加利福尼亚州
		System.out.println(getIpRegion("192.168.1.1"));    // 全球（内网）
		System.out.println(getIpRegion("127.0.0.1"));      // 全球（内网）
		System.out.println(getIpRegion("invalid.ip"));     // 未知（非法IP）
		System.out.println(getIpRegion(""));               // 未知（空IP）
	}
}
