package cn.superdesk.uniorder.common.rest.request;

import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @Description: IP相关工具类
 * @Author: linjinyu
 * @CreateDate: 2021/10/27 下午3:19
 * @UpdateUser: linjinyu
 * @UpdateDate: 2021/10/27 下午3:19
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Slf4j
public class IpUtils {

	/**
	 * 获取当前网络ip
	 *
	 * @param request
	 * @return
	 */
	public static String getIpAddr(HttpServletRequest request) {
		String ipAddress = request.getHeader("x-forwarded-for");
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getRemoteAddr();
			if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
				//根据网卡取本机配置的IP
				InetAddress inet = null;
				try {
					inet = InetAddress.getLocalHost();
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}
				ipAddress = inet.getHostAddress();
			}
		}
		// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割  //"***.***.***.***".length() = 15
		if (ipAddress != null && ipAddress.length() > 15) {
			if (ipAddress.indexOf(",") > 0) {
				ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
			}
		}
		return ipAddress;
	}

	/**
	 * 获取真实IP
	 *
	 * @param request
	 * @return
	 */
	public static String getRealIp(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		return checkIp(ip) ? ip : (
				checkIp(ip = request.getHeader("Proxy-Client-IP")) ? ip : (
						checkIp(ip = request.getHeader("WL-Proxy-Client-IP")) ? ip :
								request.getRemoteAddr()));
	}

	/**
	 * 校验IP
	 *
	 * @param ip
	 * @return
	 */
	private static boolean checkIp(String ip) {
		return !StringUtils.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip);
	}


	/**
	 * 获取操作系统,浏览器及浏览器版本信息
	 *
	 * @param request
	 * @return
	 */
	public static Map<String, String> getOsAndBrowserInfo(HttpServletRequest request) {
		String browserDetails = request.getHeader("User-Agent");
		String userAgent      = browserDetails;
		String user           = userAgent.toLowerCase();

		String os      = "";
		String browser = "";

		//=================OS Info=======================
		if (userAgent.toLowerCase().indexOf("windows") >= 0) {
			os = "Windows";
		} else if (userAgent.toLowerCase().indexOf("mac") >= 0) {
			os = "Mac";
		} else if (userAgent.toLowerCase().indexOf("x11") >= 0) {
			os = "Unix";
		} else if (userAgent.toLowerCase().indexOf("android") >= 0) {
			os = "Android";
		} else if (userAgent.toLowerCase().indexOf("iphone") >= 0) {
			os = "IPhone";
		} else {
			os = "UnKnown, More-Info: " + userAgent;
		}
		//===============Browser===========================
		if (user.contains("edge")) {
			browser = (userAgent.substring(userAgent.indexOf("Edge")).split(" ")[0]).replace("/", "-");
		} else if (user.contains("msie")) {
			String substring = userAgent.substring(userAgent.indexOf("MSIE")).split(";")[0];
			browser = substring.split(" ")[0].replace("MSIE", "IE") + "-" + substring.split(" ")[1];
		} else if (user.contains("safari") && user.contains("version")) {
			browser = (userAgent.substring(userAgent.indexOf("Safari")).split(" ")[0]).split("/")[0]
					+ "-" + (userAgent.substring(userAgent.indexOf("Version")).split(" ")[0]).split("/")[1];
		} else if (user.contains("opr") || user.contains("opera")) {
			if (user.contains("opera")) {
				browser = (userAgent.substring(userAgent.indexOf("Opera")).split(" ")[0]).split("/")[0]
						+ "-" + (userAgent.substring(userAgent.indexOf("Version")).split(" ")[0]).split("/")[1];
			} else if (user.contains("opr")) {
				browser = ((userAgent.substring(userAgent.indexOf("OPR")).split(" ")[0]).replace("/", "-"))
						.replace("OPR", "Opera");
			}

		} else if (user.contains("chrome")) {
			browser = (userAgent.substring(userAgent.indexOf("Chrome")).split(" ")[0]).replace("/", "-");
		} else if ((user.indexOf("mozilla/7.0") > -1) || (user.indexOf("netscape6") != -1) ||
				(user.indexOf("mozilla/4.7") != -1) || (user.indexOf("mozilla/4.78") != -1) ||
				(user.indexOf("mozilla/4.08") != -1) || (user.indexOf("mozilla/3") != -1)) {
			browser = "Netscape-?";

		} else if (user.contains("firefox")) {
			browser = (userAgent.substring(userAgent.indexOf("Firefox")).split(" ")[0]).replace("/", "-");
		} else if (user.contains("rv")) {
			String IEVersion = (userAgent.substring(userAgent.indexOf("rv")).split(" ")[0]).replace("rv:", "-");
			browser = "IE" + IEVersion.substring(0, IEVersion.length() - 1);
		} else {
			browser = "UnKnown, More-Info: " + userAgent;
		}
		Map<String, String> result = new HashMap<>(2);
		result.put("OS", os);
		result.put("BROWSER", browser);
		return result;
	}

	/**
	 * 判断是否是内网IP
	 *
	 * @param ip
	 * @return
	 */
	public static boolean isInner(String ip) {
		String  reg     = "(10|172|192)\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})";
		Pattern p       = Pattern.compile(reg);
		Matcher matcher = p.matcher(ip);
		return matcher.find();
	}

	/**
	 * 获取IP地址来源
	 *
	 * @param content        请求的参数 格式为:name=xxx&pwd=xxx
	 * @param encodingString 服务器端请求编码。如GBK,UTF-8等
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String getAddresses(String content, String encodingString) {

		String ip = content.substring(3);

		if (!Util.isIpAddress(ip)) {
			log.info("IP地址为空");
			return null;
		}

		// 淘宝IP宕机,目前使用Ip2region:https://github.com/lionsoul2014/ip2region
		log.info("返回的IP信息:{}", getCityInfo(ip));
		return getCityInfo(ip);

		// TODO 淘宝接口目前已经宕机,因此暂时注释下面代码
//        try {
//            // 这里调用pconline的接口
//            String urlStr = "http://ip.taobao.com/service/getIpInfo.php";
//
//            // 从http://whois.pconline.com.cn取得IP所在的省市区信息
//            String returnStr = getResult(urlStr, content, encodingString);
//
//            if (returnStr != null) {
//                // 处理返回的省市区信息
//                log.info("调用IP解析接口返回的内容:" + returnStr);
//                String[] temp = returnStr.split(",");
//                //无效IP,局域网测试
//                if (temp.length < 3) {
//                    return "0";
//                }
//
//                // 国家
//                String country = "";
//                // 区域
//                String area = "";
//                // 省
//                String region = "";
//                // 市
//                String city = "";
//                // 县
//                String county = "";
//                // 运营商
//                String isp = "";
//
//                Map<String, Object> map = JsonUtils.jsonToMap(returnStr);
//
//                if (map.get("code") != null) {
//                    Map<String, String> data = (Map<String, String>) map.get("data");
//                    country = data.get("country");
//                    area = data.get("area");
//                    region = data.get("region");
//                    city = data.get("city");
//                    county = data.get("area");
//                    isp = data.get("isp");
//                }
//
//
//                log.info("获取IP地址对应的地址" + country + "=" + area + "=" + region + "=" + city + "=" + county + "=" + isp);
//                StringBuffer result = new StringBuffer();
//                result.append(country);
//                result.append("|");
//                result.append(region);
//                result.append("|");
//                result.append(city);
//                result.append("|");
//                result.append(isp);
//
//                return result.toString();
//            }
//        } catch (Exception e) {
//            log.error(e.getMessage());
//            return null;
//        }
//        return null;
	}

	/**
	 * @param urlStr   请求的地址
	 * @param content  请求的参数 格式为:name=xxx&pwd=xxx
	 * @param encoding 服务器端请求编码。如GBK,UTF-8等
	 * @return
	 */
	private static String getResult(String urlStr, String content, String encoding) {
		URL               url        = null;
		HttpURLConnection connection = null;
		try {
			url = new URL(urlStr);
			// 新建连接实例
			connection = (HttpURLConnection) url.openConnection();

			// 设置连接超时时间,单位毫秒
			connection.setConnectTimeout(10000);

			// 设置读取数据超时时间,单位毫秒
			connection.setReadTimeout(10000);

			// 是否打开输出流 true|false
			connection.setDoOutput(true);

			// 是否打开输入流true|false
			connection.setDoInput(true);

			// 提交方法POST|GET
			connection.setRequestMethod("POST");

			// 是否缓存true|false
			connection.setUseCaches(false);

			// 打开连接端口
			connection.connect();

			// 打开输出流往对端服务器写数据
			DataOutputStream out = new DataOutputStream(connection.getOutputStream());

			// 写数据,也就是提交你的表单 name=xxx&pwd=xxx
			out.writeBytes(content);

			// 刷新
			out.flush();

			// 关闭输出流
			out.close();

			// 往对端写完数据对端服务器返回数据
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					connection.getInputStream(), encoding));

			// ,以BufferedReader流来读取
			StringBuffer buffer = new StringBuffer();
			String       line   = "";
			while ((line = reader.readLine()) != null) {
				buffer.append(line);
			}
			reader.close();
			return buffer.toString();
		} catch (Exception e) {
			log.error(e.getMessage());
			return null;
		} finally {
			if (connection != null) {
				// 关闭连接
				connection.disconnect();
			}
		}
	}

	/**
	 * unicode 转换成 中文
	 *
	 * @param theString
	 * @return
	 * @author fanhui 2007-3-15
	 */
	public 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();
	}

	/**
	 * 创建ip2region文件
	 *
	 * @return
	 */
	public static String createFtlFileByFtlArray() {
		String ftlPath = "city/";
		return createFtlFile(ftlPath, "ip2region.db");
	}

	/**
	 * 创建文件
	 *
	 * @param ftlPath
	 * @param ftlName
	 * @return
	 */
	private static String createFtlFile(String ftlPath, String ftlName) {
		InputStream certStream = null;
		try {
			// 获取当前项目所在的绝对路径
			String proFilePath = System.getProperty("user.dir");

			// 获取模板下的路径,然后存放在temp目录下　
			String newFilePath = proFilePath + File.separator + "temp" + File.separator + ftlPath;
			newFilePath = newFilePath.replace("/", File.separator);
			// 检查项目运行时的src下的对应路径
			File newFile = new File(newFilePath + ftlName);
			if (newFile.isFile() && newFile.exists()) {
				return newFilePath;
			}
			// 当项目打成jar包会运行下面的代码,并且复制一份到src路径下(具体结构看下面图片)
			certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(ftlPath + ftlName);
			byte[] certData = org.apache.commons.io.IOUtils.toByteArray(certStream);
			org.apache.commons.io.FileUtils.writeByteArrayToFile(newFile, certData);
			return newFilePath;
		} catch (Exception e) {
			log.error(e.getMessage());
		} finally {
			try {
				certStream.close();
			} catch (Exception e) {
				log.error(e.getMessage());
			}
		}
		return null;
	}

	public static String getCityInfo(String ip) {

		String dbPath = createFtlFileByFtlArray() + "ip2region.db";
		File   file   = new File(dbPath);
		if (file.exists() == false) {
			System.out.println("Error: Invalid ip2region.db file");
		}

		//查询算法
		//B-tree, B树搜索(更快)
		int algorithm = DbSearcher.BTREE_ALGORITHM;

		//Binary,使用二分搜索
		//DbSearcher.BINARY_ALGORITHM

		//Memory,加载内存(最快)
		//DbSearcher.MEMORY_ALGORITYM
		try {
			DbConfig   config   = new DbConfig();
			DbSearcher searcher = new DbSearcher(config, dbPath);

			//define the method
			Method method = null;
			switch (algorithm) {
				case DbSearcher.BTREE_ALGORITHM:
					method = searcher.getClass().getMethod("btreeSearch", String.class);
					break;
				case DbSearcher.BINARY_ALGORITHM:
					method = searcher.getClass().getMethod("binarySearch", String.class);
					break;
				case DbSearcher.MEMORY_ALGORITYM:
					method = searcher.getClass().getMethod("memorySearch", String.class);
					break;
			}

			DataBlock dataBlock = null;
			if (Util.isIpAddress(ip) == false) {
				System.out.println("Error: Invalid ip address");
			}

			dataBlock = (DataBlock) method.invoke(searcher, ip);
			String ipInfo = dataBlock.getRegion();
			if (!StringUtils.isEmpty(ipInfo)) {
				ipInfo = ipInfo.replace("|0", "");
				ipInfo = ipInfo.replace("0|", "");
			}
			return ipInfo;

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

		return null;
	}

	/**
	 * 获取IP
	 *
	 * @return
	 */
	public static String getHostIp() {
		try {
			return InetAddress.getLocalHost().getHostAddress();
		} catch (UnknownHostException e) {
		}
		return "127.0.0.1";
	}

	/**
	 * 获取主机名
	 *
	 * @return
	 */
	public static String getHostName() {
		try {
			return InetAddress.getLocalHost().getHostName();
		} catch (UnknownHostException e) {
		}
		return "未知";
	}

	public static void main(String args[]) {
		String ip           = "220.248.12.158";
		String cityIpString = getCityInfo(ip);
		System.out.println(cityIpString);
	}

}
