package org.kne.cloud.network.tun;

import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import java.nio.charset.Charset;
import java.util.*;

import org.kne.cloud.network.tun.WindowsInterfaceConverter.GUID;

/**
 * Windows DNS 设置管理类
 * 支持获取、设置和修改网络接口的 DNS 配置
 */
public class WindowsDNSManager {
    
    // 内存布局
    public static final AddressLayout POINTER = ValueLayout.ADDRESS;
    public static final ValueLayout.OfInt DWORD = ValueLayout.JAVA_INT;
    public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
    public static final ValueLayout.OfByte BYTE = ValueLayout.JAVA_BYTE;
    public static final ValueLayout.OfShort WORD = ValueLayout.JAVA_SHORT;
    
    // DNS 设置常量
    public static final int DNS_SETTINGS_VERSION1 = 0x0001;
    public static final int DNS_INTERFACE_SETTINGS_VERSION1 = 0x0001;
    public static final int DNS_INTERFACE_SETTINGS_VERSION2 = 0x0002;
    
    // DNS 设置标志
    public static final long DNS_SETTING_IPV6 = 0x0001L;
    public static final long DNS_SETTING_NAMESERVER = 0x0002L;
    public static final long DNS_SETTING_SEARCHLIST = 0x0004L;
    public static final long DNS_SETTING_REGISTRATION_ENABLED = 0x0008L;
    public static final long DNS_SETTING_REGISTER_ADAPTER_NAME = 0x0010L;
    public static final long DNS_SETTING_DOMAIN = 0x0020L;
    public static final long DNS_SETTING_HOSTNAME = 0x0040L;
    public static final long DNS_SETTINGS_ENABLE_LLMNR = 0x0080L;
    public static final long DNS_SETTINGS_QUERY_ADAPTER_NAME = 0x0100L;
    public static final long DNS_SETTING_PROFILE_NAMESERVER = 0x0200L;
    public static final long DNS_SETTING_DISABLE_UNCONSTRAINED_QUERIES = 0x0400L;
    public static final long DNS_SETTING_SUPPLEMENTAL_SEARCH_LIST = 0x0800L;
    
    // DNS_SETTINGS 结构体布局 (通用 DNS 设置)
    public static final GroupLayout DNS_SETTINGS_LAYOUT = MemoryLayout.structLayout(
        DWORD.withName("Version"),      // ULONG Version
        MemoryLayout.paddingLayout(4),
        DWORD64.withName("Flags"),      // ULONG64 Flags
        POINTER.withName("Hostname"),   // PWSTR Hostname
        POINTER.withName("Domain"),     // PWSTR Domain
        POINTER.withName("SearchList")  // PWSTR SearchList
    );
    
    // DNS_INTERFACE_SETTINGS 结构体布局 (接口特定 DNS 设置 V1)
    public static final GroupLayout DNS_INTERFACE_SETTINGS_LAYOUT = MemoryLayout.structLayout(
        DWORD.withName("Version"),                   // ULONG Version
        MemoryLayout.paddingLayout(4),
        DWORD64.withName("Flags"),                   // ULONG64 Flags
        POINTER.withName("Domain"),                  // PWSTR Domain
        POINTER.withName("NameServer"),              // PWSTR NameServer
        POINTER.withName("SearchList"),              // PWSTR SearchList
        DWORD.withName("RegistrationEnabled"),       // ULONG RegistrationEnabled
        DWORD.withName("RegisterAdapterName"),       // ULONG RegisterAdapterName
        DWORD.withName("EnableLLMNR"),               // ULONG EnableLLMNR
        DWORD.withName("QueryAdapterName"),          // ULONG QueryAdapterName
        POINTER.withName("ProfileNameServer")        // PWSTR ProfileNameServer
    );
    
    // DNS_INTERFACE_SETTINGS_EX 结构体布局 (扩展版本)
    public static final GroupLayout DNS_INTERFACE_SETTINGS_EX_LAYOUT = MemoryLayout.structLayout(
        DNS_INTERFACE_SETTINGS_LAYOUT.withName("SettingsV1"),
        DWORD.withName("DisableUnconstrainedQueries"), // ULONG DisableUnconstrainedQueries
        MemoryLayout.paddingLayout(4),
        POINTER.withName("SupplementalSearchList")     // PWSTR SupplementalSearchList
    );
    
    private static final SymbolLookup LOOKUP;
    private static final Linker LINKER = Linker.nativeLinker();
    
    // 方法句柄
    private static final MethodHandle GET_INTERFACE_DNS_SETTINGS;
    private static final MethodHandle FREE_INTERFACE_DNS_SETTINGS;
    private static final MethodHandle SET_INTERFACE_DNS_SETTINGS;
    private static final MethodHandle FREE_DNS_SETTINGS;
    private static final MethodHandle GET_DNS_SETTINGS;
    
    static {
        try {
            // 加载 dnsapi.dll
            System.loadLibrary("dnsapi");
            LOOKUP = SymbolLookup.loaderLookup();
            
            // GetInterfaceDnsSettings 函数
            // DWORD GetInterfaceDnsSettings(GUID *Interface, DNS_INTERFACE_SETTINGS *Settings);
            FunctionDescriptor getInterfaceDnsSettingsDesc = FunctionDescriptor.of(
                DWORD,      // 返回值: DWORD
                POINTER,    // Interface: GUID*
                POINTER     // Settings: DNS_INTERFACE_SETTINGS*
            );
            
            // SetInterfaceDnsSettings 函数
            // DWORD SetInterfaceDnsSettings(GUID *Interface, DNS_INTERFACE_SETTINGS *Settings);
            FunctionDescriptor setInterfaceDnsSettingsDesc = FunctionDescriptor.of(
                DWORD,      // 返回值: DWORD
                POINTER,    // Interface: GUID*
                POINTER     // Settings: DNS_INTERFACE_SETTINGS*
            );
            
            FunctionDescriptor freeInterfaceDnsSettingsDesc = FunctionDescriptor.ofVoid(
                    POINTER    
                );
            
            // FreeDnsSettings 函数
            // VOID FreeDnsSettings(DNS_SETTINGS *Settings);
            FunctionDescriptor freeDnsSettingsDesc = FunctionDescriptor.ofVoid(
                POINTER     // Settings: DNS_SETTINGS*
            );
            
            // GetDnsSettings 函数
            // DWORD GetDnsSettings(DNS_SETTINGS *Settings);
            FunctionDescriptor getDnsSettingsDesc = FunctionDescriptor.of(
                DWORD,      // 返回值: DWORD
                POINTER     // Settings: DNS_SETTINGS*
            );
            
            // 获取方法句柄
            GET_INTERFACE_DNS_SETTINGS = LINKER.downcallHandle(
                LOOKUP.find("GetInterfaceDnsSettings").orElseThrow(),
                getInterfaceDnsSettingsDesc
            );
            
            SET_INTERFACE_DNS_SETTINGS = LINKER.downcallHandle(
                LOOKUP.find("SetInterfaceDnsSettings").orElseThrow(),
                setInterfaceDnsSettingsDesc
            );
            
            FREE_DNS_SETTINGS = LINKER.downcallHandle(
                    LOOKUP.find("FreeDnsSettings").orElseThrow(),
                    freeInterfaceDnsSettingsDesc
                );
            
            FREE_INTERFACE_DNS_SETTINGS = LINKER.downcallHandle(
                LOOKUP.find("FreeInterfaceDnsSettings").orElseThrow(),
                freeDnsSettingsDesc
            );
            
            GET_DNS_SETTINGS = LINKER.downcallHandle(
                LOOKUP.find("GetDnsSettings").orElseThrow(),
                getDnsSettingsDesc
            );
            
        } catch (Throwable e) {
            throw new RuntimeException("Failed to initialize Windows DNS manager", e);
        }
    }
    
    /**
     * DNS 设置信息类 (Java 对象版本)
     */
    public static class DnsInterfaceSettings {
        private int version;
        private long flags;
        private String domain;
        private List<String> nameServers;
        private List<String> searchList;
        private boolean registrationEnabled;
        private boolean registerAdapterName;
        private boolean enableLLMNR;
        private boolean queryAdapterName;
        private String profileNameServer;
        private boolean disableUnconstrainedQueries;
        private List<String> supplementalSearchList;
        
        public DnsInterfaceSettings() {
            this.version = DNS_INTERFACE_SETTINGS_VERSION1;
            this.flags = 0;
        }
        
        // Getters and Setters
        public int getVersion() { return version; }
        public void setVersion(int version) { this.version = version; }
        
        public long getFlags() { return flags; }
        public void setFlags(long flags) { this.flags = flags; }
        
        public String getDomain() { return domain; }
        public void setDomain(String domain) { this.domain = domain; }
        
        public List<String> getNameServers() { return nameServers; }
        public void setNameServers(List<String> nameServers) { this.nameServers = nameServers; }
        
        public List<String> getSearchList() { return searchList; }
        public void setSearchList(List<String> searchList) { this.searchList = searchList; }
        
        public boolean isRegistrationEnabled() { return registrationEnabled; }
        public void setRegistrationEnabled(boolean registrationEnabled) { 
            this.registrationEnabled = registrationEnabled; 
        }
        
        public boolean isRegisterAdapterName() { return registerAdapterName; }
        public void setRegisterAdapterName(boolean registerAdapterName) { 
            this.registerAdapterName = registerAdapterName; 
        }
        
        public boolean isEnableLLMNR() { return enableLLMNR; }
        public void setEnableLLMNR(boolean enableLLMNR) { this.enableLLMNR = enableLLMNR; }
        
        public boolean isQueryAdapterName() { return queryAdapterName; }
        public void setQueryAdapterName(boolean queryAdapterName) { 
            this.queryAdapterName = queryAdapterName; 
        }
        
        public String getProfileNameServer() { return profileNameServer; }
        public void setProfileNameServer(String profileNameServer) { 
            this.profileNameServer = profileNameServer; 
        }
        
        public boolean isDisableUnconstrainedQueries() { return disableUnconstrainedQueries; }
        public void setDisableUnconstrainedQueries(boolean disableUnconstrainedQueries) { 
            this.disableUnconstrainedQueries = disableUnconstrainedQueries; 
        }
        
        public List<String> getSupplementalSearchList() { return supplementalSearchList; }
        public void setSupplementalSearchList(List<String> supplementalSearchList) { 
            this.supplementalSearchList = supplementalSearchList; 
        }
        
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("DNS Interface Settings:\n");
            sb.append("  Version: ").append(version).append("\n");
            sb.append("  Flags: 0x").append(Long.toHexString(flags)).append("\n");
            sb.append("  Domain: ").append(domain != null ? domain : "(null)").append("\n");
            sb.append("  Name Servers: ").append(nameServers).append("\n");
            sb.append("  Search List: ").append(searchList).append("\n");
            sb.append("  Registration Enabled: ").append(registrationEnabled).append("\n");
            sb.append("  Register Adapter Name: ").append(registerAdapterName).append("\n");
            sb.append("  Enable LLMNR: ").append(enableLLMNR).append("\n");
            sb.append("  Query Adapter Name: ").append(queryAdapterName).append("\n");
            sb.append("  Profile Name Server: ").append(profileNameServer).append("\n");
            sb.append("  Disable Unconstrained Queries: ").append(disableUnconstrainedQueries).append("\n");
            sb.append("  Supplemental Search List: ").append(supplementalSearchList);
            return sb.toString();
        }
    }
    
    /**
     * 从网卡获取 DNS 设置
     * @param interfaceGuid 网卡的 GUID
     * @return DNS 设置对象
     */
    public static DnsInterfaceSettings getInterfaceDnsSettings(GUID interfaceGuid,DnsInterfaceSettings oldSettings) {
        try (Arena arena = Arena.ofConfined()) {
            // 创建 GUID 内存段
            MemorySegment guidSegment = interfaceGuid.toMemorySegment( arena);
            
            // 分配 DNS_INTERFACE_SETTINGS 结构体 (版本1)
            MemorySegment dnsSettings = createDnsInterfaceSettingsMemory(oldSettings, arena);
            
            // 设置版本
            dnsSettings.set(DWORD, 0, DNS_INTERFACE_SETTINGS_VERSION1);
            
            // 调用 GetInterfaceDnsSettings
            int result = (int) GET_INTERFACE_DNS_SETTINGS.invokeExact(
                guidSegment,
                dnsSettings
            );
            
            if (result != 0) { // NO_ERROR = 0
                throw new WindowsAPIException("GetInterfaceDnsSettings failed", result);
            }
            DnsInterfaceSettings resultv=parseDnsInterfaceSettings(dnsSettings, arena);
            FREE_INTERFACE_DNS_SETTINGS.invokeExact(dnsSettings);
            // 解析结构体为 Java 对象
            return resultv;
            
        } catch (Throwable e) {
            throw new RuntimeException("Error getting interface DNS settings", e);
        }
    }
    
    /**
     * 应用 DNS 设置到网卡
     * @param interfaceGuid 网卡的 GUID
     * @param settings DNS 设置对象
     * @return 操作结果 (0 = 成功)
     */
    public static void setInterfaceDnsSettings(GUID interfaceGuid, DnsInterfaceSettings settings) {
        try (Arena arena = Arena.ofConfined()) {
            // 创建 GUID 内存段
            MemorySegment guidSegment = interfaceGuid.toMemorySegment( arena);
            
            // 创建 DNS_INTERFACE_SETTINGS 结构体
            MemorySegment dnsSettings = createDnsInterfaceSettingsMemory(settings, arena);
            
            // 调用 SetInterfaceDnsSettings
            int result= (int) SET_INTERFACE_DNS_SETTINGS.invokeExact(
                guidSegment,
                dnsSettings
            );
            
            if (result != 0) { // NO_ERROR = 0
                throw new WindowsAPIException("SetInterfaceDnsSettings failed", result);
            }
        } catch (Throwable e) {
            throw new RuntimeException("Error setting interface DNS settings", e);
        }
    }
    
    /**
     * 解析 DNS_INTERFACE_SETTINGS 结构体为 Java 对象
     */
    private static DnsInterfaceSettings parseDnsInterfaceSettings(MemorySegment dnsSettings, Arena arena) {
        DnsInterfaceSettings settings = new DnsInterfaceSettings();
        
        // 读取基本字段
        int version = dnsSettings.get(DWORD, 0);
        settings.setVersion(version);
        
        long flags = dnsSettings.get(DWORD64, 8);
        settings.setFlags(flags);
        
        // 读取字符串字段
        MemorySegment domainPtr = dnsSettings.get(POINTER, 16);
        if (!domainPtr.equals(MemorySegment.NULL)) {
            String domain = readWideString(domainPtr, arena);
            settings.setDomain(domain);
        }else {
        	settings.setDomain(null);
        }
        
        // 读取 NameServer (可能是多个服务器，用空格分隔)
        MemorySegment nameServerPtr = dnsSettings.get(POINTER, 24);
        if (!nameServerPtr.equals(MemorySegment.NULL)) {
            String nameServerStr = readWideString(nameServerPtr, arena);
            if (nameServerStr != null && !nameServerStr.isEmpty()) {
                String[] servers = nameServerStr.split("\\s+");
                settings.setNameServers(Arrays.asList(servers));
            }
        }else {
        	settings.setNameServers(null);
        }
        
        // 读取 SearchList (可能是多个域名，用空格分隔)
        MemorySegment searchListPtr = dnsSettings.get(POINTER, 32);
        if (!searchListPtr.equals(MemorySegment.NULL)) {
            String searchListStr = readWideString(searchListPtr, arena);
            if (searchListStr != null && !searchListStr.isEmpty()) {
                String[] domains = searchListStr.split("\\s+");
                settings.setSearchList(Arrays.asList(domains));
            }
        }else {
        	settings.setSearchList(null);
        }
        
        // 读取布尔值字段
        int registrationEnabled = dnsSettings.get(DWORD, 40);
        settings.setRegistrationEnabled(registrationEnabled != 0);
        
        int registerAdapterName = dnsSettings.get(DWORD, 44);
        settings.setRegisterAdapterName(registerAdapterName != 0);
        
        int enableLLMNR = dnsSettings.get(DWORD, 48);
        settings.setEnableLLMNR(enableLLMNR != 0);
        
        int queryAdapterName = dnsSettings.get(DWORD, 52);
        settings.setQueryAdapterName(queryAdapterName != 0);
        
        // 读取 ProfileNameServer
        MemorySegment profileNameServerPtr = dnsSettings.get(POINTER, 56);
        if (!profileNameServerPtr.equals(MemorySegment.NULL)) {
            String profileNameServer = readWideString(profileNameServerPtr, arena);
            settings.setProfileNameServer(profileNameServer);
        }else {
        	settings.setProfileNameServer(null);
        }
        
        return settings;
    }
    
    /**
     * 创建 DNS_INTERFACE_SETTINGS 结构体的内存表示
     */
    private static MemorySegment createDnsInterfaceSettingsMemory(DnsInterfaceSettings settings, Arena arena) {
        // 分配结构体内存
        MemorySegment dnsSettings = arena.allocate(DNS_INTERFACE_SETTINGS_LAYOUT);
        
        // 设置版本和标志
        dnsSettings.set(DWORD, 0, settings.getVersion());
        dnsSettings.set(DWORD64, 8, settings.getFlags());
        
        // 设置 Domain
        if (settings.getDomain() != null) {
            MemorySegment domainStr = toWideString(settings.getDomain(), arena);
            dnsSettings.set(POINTER, 16, domainStr);
        } else {
            dnsSettings.set(POINTER, 16, MemorySegment.NULL);
        }
        
        // 设置 NameServer (多个服务器用空格分隔)
        if (settings.getNameServers()!=null) {
            String nameServerStr = String.join(" ", settings.getNameServers());
            MemorySegment nameServerSegment = toWideString(nameServerStr, arena);
            dnsSettings.set(POINTER, 24, nameServerSegment);
        } else {
            dnsSettings.set(POINTER, 24, MemorySegment.NULL);
        }
        
        // 设置 SearchList (多个域名用空格分隔)
        if (settings.getSearchList()!=null) {
            String searchListStr = String.join(" ", settings.getSearchList());
            MemorySegment searchListSegment = toWideString(searchListStr, arena);
            dnsSettings.set(POINTER, 32, searchListSegment);
        } else {
            dnsSettings.set(POINTER, 32, MemorySegment.NULL);
        }
        
        // 设置布尔值字段
        dnsSettings.set(DWORD, 40, settings.isRegistrationEnabled() ? 1 : 0);
        dnsSettings.set(DWORD, 44, settings.isRegisterAdapterName() ? 1 : 0);
        dnsSettings.set(DWORD, 48, settings.isEnableLLMNR() ? 1 : 0);
        dnsSettings.set(DWORD, 52, settings.isQueryAdapterName() ? 1 : 0);
        
        // 设置 ProfileNameServer
        if (settings.getProfileNameServer() != null ) {
            MemorySegment profileNameServerSegment = toWideString(settings.getProfileNameServer(), arena);
            dnsSettings.set(POINTER, 56, profileNameServerSegment);
        } else {
            dnsSettings.set(POINTER, 56, MemorySegment.NULL);
        }
        
        return dnsSettings;
    }
    
    
    
  
   
    
    
    
    /**
     * 将 Java String 转换为 Windows 宽字符串 (UTF-16 LE)
     */
    private static MemorySegment toWideString(String str, Arena arena) {
        if (str == null ) {
            return MemorySegment.NULL;
        }
        
        byte[] utf16Bytes = str.getBytes(java.nio.charset.StandardCharsets.UTF_16LE);
        MemorySegment segment = arena.allocate(utf16Bytes.length + 2);
        segment.copyFrom(MemorySegment.ofArray(utf16Bytes));
        
        // 添加 null 终止符
        segment.set(ValueLayout.JAVA_BYTE, utf16Bytes.length, (byte) 0);
        segment.set(ValueLayout.JAVA_BYTE, utf16Bytes.length + 1, (byte) 0);
        
        return segment;
    }
    
    /**
     * 读取 Windows 宽字符串
     */
    private static String readWideString(MemorySegment strPtr, Arena arena) {
        if (strPtr.equals(MemorySegment.NULL)) {
            return null;
        }
        strPtr= strPtr.reinterpret(0xffffffffL);
        //return strPtr.getString(0,Charset.forName("UTF-16"));
        try {
            // 计算字符串长度 (找到 null 终止符)
            long length = 0;
            while (true) {
                short ch = strPtr.get(ValueLayout.JAVA_SHORT, length * 2);
                if (ch == 0) {
                    break;
                }
                length++;
            }
            
            // 读取字符串数据
            byte[] bytes = new byte[(int) (length * 2)];
            MemorySegment.copy(strPtr, 0, MemorySegment.ofArray(bytes), 0, bytes.length);
            
            return new String(bytes, java.nio.charset.StandardCharsets.UTF_16LE);
        } catch (Exception e) {
            return null;
        }
    }
    
   
  
}