package com.bocloud.ims.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * 获取本地IP地址工具类
 *
 * @author sxp
 * @since 2023/7/4
 */
public class LocalAddressUtils {
    private static final Logger logger = LoggerFactory.getLogger(LocalAddressUtils.class);

    public static final String LOCALHOST = "127.0.0.1";
    public static final String ANY_HOST = "0.0.0.0";
    private static InetAddress LOCAL_ADDRESS = null;

    /**
     * 获取当前主机的IP地址
     * <p>
     * 参考：com.alibaba.dubbo.common.utils.NetUtils#getLocalAddress <br>
     * 优先使用InetAddress获取IP，获取不到再使用NetworkInterface <br>
     * </p>
     *
     * @return 如果获取不到有效的InetAddress对象，返回127.0.0.1
     * @author sxp
     * @since 2023/7/4
     */
    public static String getLocalHostAddress() {
        InetAddress address = getLocalAddress();
        return (address == null) ? LOCALHOST : address.getHostAddress();
    }

    private static InetAddress getLocalAddress() {
        if (LOCAL_ADDRESS != null) {
            return LOCAL_ADDRESS;
        }
        InetAddress localAddress = getLocalAddress0();
        LOCAL_ADDRESS = localAddress;
        return localAddress;
    }

    private static InetAddress getLocalAddress0() {
        List<InetAddress> inetAddressList = getIP4ByNetworkInterface(true);

        try {
            InetAddress localAddress = InetAddress.getLocalHost();

            if (isValidAddress(localAddress)) {
                // 防止hosts文件或DNS解析错误，导致获取错误IP地址，检查该地址是否出现在网卡配置信息中
                if (inetAddressList.contains(localAddress)) {
                    return localAddress;
                }
            }
        } catch (UnknownHostException e) {
            // ignore
        }

        for (InetAddress address : inetAddressList) {
            if (isValidAddress(address)) {
                return address;
            }
        }

        return null;
    }

    /**
     * 获取本机的网络接口的详细信息
     * <p>
     * 支持对网卡状态进行判断
     * </p>
     *
     * @author sxp
     * @since 2023/7/4
     */
    public static List<InetAddress> getIP4ByNetworkInterface(boolean checkStatus) {
        List<InetAddress> inetAddressList = new ArrayList<>(4);

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

            if (allNetInterfaces == null) {
                logger.error("获取NetworkInterface.getNetworkInterfaces失败!");
                return inetAddressList;
            }

            InetAddress address;
            Enumeration<InetAddress> addresses;
            NetworkInterface netInterface;
            boolean isUp;

            while (allNetInterfaces.hasMoreElements()) {
                netInterface = allNetInterfaces.nextElement();
                if (checkStatus) {
                    isUp = netInterface.isUp();
                    if (!isUp) {
                        continue;
                    }
                }
                addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    address = addresses.nextElement();
                    if (address != null && address instanceof Inet4Address) {
                        inetAddressList.add(address);
                    }
                }
            }
        } catch (SocketException e) {
            logger.error(e.getMessage(), e);
        }

        return inetAddressList;
    }

    private static boolean isValidAddress(InetAddress address) {
        if (address == null || address.isLoopbackAddress()) {
            return false;
        }
        String ip = address.getHostAddress();
        if (ip == null) {
            return false;
        }
        return (!ANY_HOST.equals(ip) && !LOCALHOST.equals(ip) && IpValidator.isValidIPv4(ip));
    }

}
