package com.seer.teach.common.utils;

import java.net.*;
import java.util.Enumeration;

/**
 * 工具类：用于获取当前容器所在的宿主机 IP 地址。
 * <p>
 * 支持两种获取方式：
 * <ul>
 *     <li>优先从环境变量 HOST_IP 获取（推荐：容器启动时传入）</li>
 *     <li>回退使用主机网卡 IP（适用于 --net=host 模式）</li>
 * </ul>
 * 常用于部署在 Docker 容器中的 Netty 服务，需要将宿主机 IP 注册到 Redis 以实现设备路由。
 */
public class HostIpResolver {

    /**
     * 获取当前容器所属宿主机的 IP 地址。
     * <p>
     * 优先从环境变量 {@code HOST_IP} 获取；如果不存在则自动枚举网卡获取本地非回环 IPv4 地址。
     *
     * @return 宿主机的 IPv4 地址，如无法获取则返回字符串 {@code "UNKNOWN"}
     */
    public static String getHostIp() {
        String envIp = System.getenv("HOST_IP");
        if (envIp != null && !envIp.trim().isEmpty()) {
            return envIp;
        }

        return getLocalIpAddress();
    }

    /**
     * 从本地网卡中查找第一个可用的非回环 IPv4 地址。
     * <p>
     * 注意：该方法只在 Docker 使用 host 网络模式时有效；
     * 在 bridge 网络模式下只能获取容器内部 IP。
     *
     * @return 本机的 IPv4 地址，如果获取失败则返回 {@code "UNKNOWN"}
     */
    private static String getLocalIpAddress() {
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                // 跳过环回地址、虚拟接口、不可用接口
                if (ni.isLoopback() || ni.isVirtual() || !ni.isUp()) continue;

                Enumeration<InetAddress> addresses = ni.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    // 仅获取 IPv4 地址，且排除环回地址（127.0.0.1）
                    if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
                        return addr.getHostAddress();
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return "UNKNOWN";
    }
}
