//
//  NetworkInterface.swift
//  punchnet
//
//  Created by 安礼成 on 2025/8/3.
//


//
//  NetworkInterface.swift
//  Tun
//
//  Created by 安礼成 on 2024/1/19.
//

import Foundation
import Network

public struct NetworkInterface {
    public let name: String
    public let ip: String
    public let netmask: String
}

public struct NetworkInterfaceManager {
    /**
    获取网卡信息, (let name: String let ip: String let netmask: String)
     */
    public static func getInterfaces() -> [NetworkInterface] {
        var interfaces: [NetworkInterface] = []
        
        // Get list of all interfaces on the local machine:
        var ifaddr : UnsafeMutablePointer<ifaddrs>? = nil
        if getifaddrs(&ifaddr) == 0 {
            
            // For each interface ...
            var ptr = ifaddr
            while( ptr != nil) {
                
                let flags = Int32(ptr!.pointee.ifa_flags)
                var addr = ptr!.pointee.ifa_addr.pointee
                
                // Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
                if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
                    if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
                        
                        var mask = ptr!.pointee.ifa_netmask.pointee
                        
                        // Convert interface address to a human readable string:
                        let zero  = CChar(0)
                        var hostname = [CChar](repeating: zero, count: Int(NI_MAXHOST))
                        var netmask =  [CChar](repeating: zero, count: Int(NI_MAXHOST))
                        if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
                                        nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                            let address = String(cString: hostname)

                            let name = ptr!.pointee.ifa_name!
                            let ifname = String(cString: name)
                            
                            if (getnameinfo(&mask, socklen_t(mask.sa_len), &netmask, socklen_t(netmask.count), nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                                let netmaskIP = String(cString: netmask)
                                
                                interfaces.append(NetworkInterface(name: ifname, ip: address, netmask: netmaskIP))
                            }
                        }
                    }
                }
                ptr = ptr!.pointee.ifa_next
            }
            freeifaddrs(ifaddr)
        }
        
        return interfaces
    }

    // 获取本地网卡中的公网IPv6地址
    public static func getPublicIPv6Address() -> String? {
        return self.getPublicIPv6Interface()?.ip
    }
    
    // 获取本地网卡中的公网IPv6网卡
    public static func getPublicIPv6Interface() -> NetworkInterface? {
        let interfaces = self.getInterfaces()

        return interfaces.first { interface in
            !interface.name.hasPrefix("utun")
            && self.isPublicIPv6(interface.ip)
        }
    }

    /// 判断一个 IPv6 字符串是否是公网 IPv6
    public static func isPublicIPv6(_ ipString: String) -> Bool {
        let normalizedIp = String(ipString.split(separator: "%", maxSplits: 1, omittingEmptySubsequences: false).first ?? "")
        guard let ipv6 = IPv6Address(normalizedIp) else {
            return false
        }
        return self.isPublicIPv6(ipv6.rawValue)
    }

    /// 判断 16 字节 IPv6 地址是否是公网 IPv6
    public static func isPublicIPv6(_ raw: Data) -> Bool {
        guard raw.count == 16 else {
            return false
        }

        let bytes = [UInt8](raw)

        // 1. 排除 unspecified ::
        if bytes.allSatisfy({ $0 == 0 }) {
            return false
        }

        // 2. 排除 loopback ::1
        if bytes.dropLast().allSatisfy({ $0 == 0 }) && bytes[15] == 1 {
            return false
        }

        // 3. 排除 multicast ff00::/8
        if bytes[0] == 0xFF {
            return false
        }

        // 4. 排除 link-local fe80::/10
        // 即首字节 0xFE，第二字节前两位是 10（二进制）
        if bytes[0] == 0xFE && (bytes[1] & 0xC0) == 0x80 {
            return false
        }

        // 5. 排除 ULA fc00::/7
        // 即首字节前 7 位是 1111110
        if (bytes[0] & 0xFE) == 0xFC {
            return false
        }

        // 6. 判断是否属于 2000::/3
        // 即首字节前 3 位是 001
        return (bytes[0] & 0xE0) == 0x20
    }

}
