package org.kne.cloud.network.tun;
import java.lang.classfile.AnnotationValue.OfLong;
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.UUID;

/**
 * Windows 网络接口 LUID 和 GUID 转换工具类
 * 提供 ConvertInterfaceLuidToGuid 和 ConvertInterfaceGuidToLuid 的 Java 实现
 */
public class WindowsInterfaceConverter {
    
    // Windows API 常量
    private static final long INVALID_LUID_VALUE = 0L;
    
    // 内存布局
    public static final AddressLayout POINTER = ValueLayout.ADDRESS;
    public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
    
    // GUID 结构布局 (128位，16字节)
    public static final GroupLayout GUID_LAYOUT = MemoryLayout.structLayout(
        ValueLayout.JAVA_INT.withName("Data1"),      // unsigned long
        ValueLayout.JAVA_SHORT.withName("Data2"),     // unsigned short
        ValueLayout.JAVA_SHORT.withName("Data3"),     // unsigned short
        MemoryLayout.sequenceLayout(8, ValueLayout.JAVA_BYTE).withName("Data4")  // unsigned char[8]
    ).withByteAlignment(4);
    
    // LUID 结构布局 (64位)
    public static final GroupLayout LUID_LAYOUT = MemoryLayout.structLayout(
        ValueLayout.JAVA_LONG.withName("Value")  // unsigned __int64
    );
    
    // NET_LUID 联合布局 (Windows中的NET_LUID可以是LUID或IF_INDEX)
    public static final GroupLayout NET_LUID_LAYOUT = MemoryLayout.structLayout(
        MemoryLayout.unionLayout(
            MemoryLayout.structLayout(
                ValueLayout.JAVA_LONG.withName("Value")  // LUID
            ).withName("Luid"),
            MemoryLayout.structLayout(
                MemoryLayout.paddingLayout(24),
                ValueLayout.JAVA_INT.withName("Reserved"),    // 保留字段
                ValueLayout.JAVA_INT.withName("NetLuidIndex"), // 网络LUID索引
                ValueLayout.JAVA_INT.withName("IfIndex")       // 接口索引
            ).withName("Info")
        ).withName("u")
    );
    
    private static final SymbolLookup LOOKUP;
    private static final Linker LINKER = Linker.nativeLinker();
    private static final Arena GLOBAL_ARENA = Arena.ofAuto();
    
    // 方法句柄
    private static final MethodHandle CONVERT_LUID_TO_GUID;
    private static final MethodHandle CONVERT_GUID_TO_LUID;
    
    static {
        try {
            // 加载 iphlpapi.dll
            System.loadLibrary("iphlpapi");
            LOOKUP = SymbolLookup.loaderLookup();
            
            // 定义函数描述符
            // DWORD ConvertInterfaceLuidToGuid(const NET_LUID *Luid, GUID *Guid);
            FunctionDescriptor luidToGuidDesc = FunctionDescriptor.of(
                ValueLayout.JAVA_INT,  // DWORD 返回值
                POINTER,               // const NET_LUID *Luid
                POINTER                // GUID *Guid
            );
            
            // DWORD ConvertInterfaceGuidToLuid(const GUID *Guid, NET_LUID *Luid);
            FunctionDescriptor guidToLuidDesc = FunctionDescriptor.of(
                ValueLayout.JAVA_INT,  // DWORD 返回值
                POINTER,               // const GUID *Guid
                POINTER                // NET_LUID *Luid
            );
            
            // 获取方法句柄
            CONVERT_LUID_TO_GUID = LINKER.downcallHandle(
                LOOKUP.find("ConvertInterfaceLuidToGuid").orElseThrow(),
                luidToGuidDesc
            );
            
            CONVERT_GUID_TO_LUID = LINKER.downcallHandle(
                LOOKUP.find("ConvertInterfaceGuidToLuid").orElseThrow(),
                guidToLuidDesc
            );
            
        } catch (Throwable e) {
            throw new RuntimeException("Failed to initialize Windows interface converter", e);
        }
    }
    
    /**
     * LUID 结构
     */
    public static class LUID {
        private final long value;
        
        public LUID(long value) {
            this.value = value;
        }
        
        public long getValue() {
            return value;
        }
        
        public static LUID fromMemorySegment(MemorySegment segment) {
            if (segment.byteSize() < 8) {
                throw new IllegalArgumentException("Memory segment too small for LUID");
            }
            long value = segment.get(ValueLayout.JAVA_LONG, 0);
            return new LUID(value);
        }
        
        public MemorySegment toMemorySegment(Arena arena) {
            MemorySegment segment = arena.allocate(LUID_LAYOUT);
            segment.set(ValueLayout.JAVA_LONG, 0, value);
            return segment;
        }
        
        @Override
        public String toString() {
            return String.format("0x%016X", value);
        }
    }
    
    /**
     * GUID 结构
     */
    public static class GUID {
        private final UUID uuid;
        
        public GUID(UUID uuid) {
            this.uuid = uuid;
        }
        
        public GUID(String guidString) {
            this.uuid = UUID.fromString(guidString);
        }
        
        public GUID(int data1, short data2, short data3, byte[] data4) {
            if (data4.length != 8) {
                throw new IllegalArgumentException("Data4 must be exactly 8 bytes");
            }
            
            long mostSigBits = (((long) data1) << 32) | (((long)( data2&0xffff) )<< 16) | (long)(data3&0xffff);
            ByteBuffer bb = ByteBuffer.wrap(data4).order(ByteOrder.BIG_ENDIAN);
            long leastSigBits = bb.getLong();
            
            this.uuid = new UUID(mostSigBits, leastSigBits);
        }
        
        public UUID getUuid() {
            return uuid;
        }
        
        public static GUID fromMemorySegment(MemorySegment segment) {
            if (segment.byteSize() < GUID_LAYOUT.byteSize()) {
                throw new IllegalArgumentException("Memory segment too small for GUID");
            }
            
            int data1 = segment.get(ValueLayout.JAVA_INT, 0);
            short data2 = segment.get(ValueLayout.JAVA_SHORT, 4);
            short data3 = segment.get(ValueLayout.JAVA_SHORT, 6);
            
            byte[] data4 = new byte[8];
            MemorySegment data4Segment = segment.asSlice(8, 8);
            for (int i = 0; i < 8; i++) {
                data4[i] = data4Segment.get(ValueLayout.JAVA_BYTE, i);
            }
            
            return new GUID(data1, data2, data3, data4);
        }
        
        public MemorySegment toMemorySegment(Arena arena) {
            MemorySegment segment = arena.allocate(GUID_LAYOUT);
            
            long mostSigBits = uuid.getMostSignificantBits();
            long leastSigBits = uuid.getLeastSignificantBits();
            
            // Data1 = 高32位
            int data1 = (int) (mostSigBits >> 32);
            // Data2 = 接下来的16位
            short data2 = (short) ((mostSigBits >> 16) & 0xFFFF);
            // Data3 = 最后的16位
            short data3 = (short) (mostSigBits & 0xFFFF);
            
            segment.set(ValueLayout.JAVA_INT, 0, data1);
            segment.set(ValueLayout.JAVA_SHORT, 4, data2);
            segment.set(ValueLayout.JAVA_SHORT, 6, data3);
            
            // Data4 = 低64位的字节数组
            ByteBuffer bb = ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN);
            bb.putLong(leastSigBits);
            byte[] data4 = bb.array();
            
            MemorySegment data4Segment = segment.asSlice(8, 8);
            for (int i = 0; i < 8; i++) {
                data4Segment.set(ValueLayout.JAVA_BYTE, i, data4[i]);
            }
            
            return segment;
        }
        
        @Override
        public String toString() {
            return uuid.toString().toUpperCase();
        }
        
        public String toRegistryFormat() {
            return "{" + toString() + "}";
        }
    }
    
    /**
     * 将 LUID 转换为 GUID
     * @param luid LUID 值
     * @return 对应的 GUID
     */
    public static GUID convertLuidToGuid(LUID luid) {
        try (Arena arena = Arena.ofConfined()) {
            // 准备 NET_LUID 结构
            MemorySegment netLuid = arena.allocate(NET_LUID_LAYOUT);
            netLuid.set(ValueLayout.JAVA_LONG, 0, luid.getValue());
            
            // 准备 GUID 输出缓冲区
            MemorySegment guidBuffer = arena.allocate(GUID_LAYOUT);
            
            // 调用 Windows API
            int result = (int) CONVERT_LUID_TO_GUID.invokeExact(
                netLuid,
                guidBuffer
            );
            
            // 检查结果
            if (result != 0) { // NO_ERROR = 0
                throw new WindowsAPIException("ConvertInterfaceLuidToGuid failed with error: " + result);
            }
            
            return GUID.fromMemorySegment(guidBuffer);
        } catch (Throwable e) {
            throw new RuntimeException("Error converting LUID to GUID", e);
        }
    }
    
    /**
     * 将 LUID 转换为 GUID（简化版本）
     * @param luidValue LUID 的 long 值
     * @return 对应的 GUID
     */
    public static GUID convertLuidToGuid(long luidValue) {
        return convertLuidToGuid(new LUID(luidValue));
    }
    
    /**
     * 将 GUID 转换为 LUID
     * @param guid GUID
     * @return 对应的 LUID
     */
    public static LUID convertGuidToLuid(GUID guid) {
        try (Arena arena = Arena.ofConfined()) {
            // 准备 GUID 结构
            MemorySegment guidBuffer = guid.toMemorySegment(arena);
            
            // 准备 NET_LUID 输出缓冲区
            MemorySegment netLuidBuffer = arena.allocate(NET_LUID_LAYOUT);
            
            // 调用 Windows API
            int result = (int) CONVERT_GUID_TO_LUID.invokeExact(
                guidBuffer,
                netLuidBuffer
            );
            
            // 检查结果
            if (result != 0) { // NO_ERROR = 0
                throw new WindowsAPIException("ConvertInterfaceGuidToLuid failed with error: " + result);
            }
            
            // 从 NET_LUID 结构中提取 LUID 值
            long luidValue = netLuidBuffer.get(ValueLayout.JAVA_LONG, 0);
            return new LUID(luidValue);
        } catch (Throwable e) {
            throw new RuntimeException("Error converting GUID to LUID", e);
        }
    }
    
    /**
     * 将 GUID 字符串转换为 LUID
     * @param guidString GUID 字符串
     * @return 对应的 LUID
     */
    public static LUID convertGuidToLuid(String guidString) {
        return convertGuidToLuid(new GUID(guidString));
    }
    
    /**
     * 获取所有网络接口的 LUID 和 GUID 映射
     * @return LUID 到 GUID 的映射
     */
    public static java.util.Map<LUID, GUID> getAllNetworkInterfaces() {
        // 注意：这个函数需要更多的 Windows API 调用
        // 这里只是示例，实际实现需要调用 GetAdaptersAddresses 等函数
        java.util.Map<LUID, GUID> interfaces = new java.util.HashMap<>();
        
        try {
            // 这里可以添加调用 GetAdaptersAddresses 的代码
            // 遍历所有适配器，获取它们的 LUID 和 GUID
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return interfaces;
    }
    
    /**
     * Windows API 异常
     */
    public static class WindowsAPIException extends RuntimeException {
        private final int errorCode;
        
        public WindowsAPIException(String message) {
            super(message);
            this.errorCode = -1;
        }
        
        public WindowsAPIException(String message, int errorCode) {
            super(message + " (Error code: " + errorCode + ")");
            this.errorCode = errorCode;
        }
        
        public int getErrorCode() {
            return errorCode;
        }
    }
    
    /**
     * 测试方法
     */
    public static void main(String[] args) {
        try {
            System.out.println("Windows Interface Converter Test");
            System.out.println("=================================");
            
            // 测试 1: 创建一个测试 GUID 并转换
            String testGuidStr = "12345678-1234-1234-1234-123456789012";
            System.out.println("Test GUID: " + testGuidStr);
            
            GUID testGuid = new GUID(testGuidStr);
            System.out.println("Created GUID: " + testGuid);
            
            // 尝试将 GUID 转换为 LUID
            try {
                LUID luidFromGuid = convertGuidToLuid(testGuid);
                System.out.println("LUID from GUID: " + luidFromGuid);
                
                // 再转换回 GUID
                GUID guidFromLuid = convertLuidToGuid(luidFromGuid);
                System.out.println("GUID from LUID: " + guidFromLuid);
                System.out.println("Conversion successful: " + guidFromLuid.equals(testGuid));
            } catch (Exception e) {
                System.out.println("Note: This GUID might not correspond to a real interface: " + e.getMessage());
            }
            
            System.out.println("\nTesting with Wintun adapter:");
            System.out.println("=============================");
            
            // 测试 2: 与 Wintun 驱动结合使用
            // 假设你已经有了一个 Wintun 适配器
            // 这里展示如何获取适配器的 LUID 并转换为 GUID
            
            // 这段代码需要在有 Wintun 适配器的情况下运行
            
            WintunDriver.WintunAdapterHandle adapter = WintunDriver.openAdapter("MyWintun");
            long luid = WintunDriver.getAdapterLuid(adapter);
            LUID adapterLuid = new LUID(luid);
            System.out.println("Wintun Adapter LUID: " + adapterLuid);
            
            GUID adapterGuid = convertLuidToGuid(adapterLuid);
            System.out.println("Wintun Adapter GUID: " + adapterGuid);
            
            // 清理
            WintunDriver.closeAdapter(adapter);
            
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 辅助方法：从字节数组创建 GUID
     */
    public static GUID createGuidFromBytes(byte[] bytes) {
        if (bytes.length != 16) {
            throw new IllegalArgumentException("GUID must be 16 bytes");
        }
        
        ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
        long mostSigBits = bb.getLong();
        long leastSigBits = bb.getLong();
        
        return new GUID(new UUID(mostSigBits, leastSigBits));
    }
    
    /**
     * 辅助方法：将 GUID 转换为字节数组
     */
    public static byte[] guidToBytes(GUID guid) {
        ByteBuffer bb = ByteBuffer.allocate(16).order(ByteOrder.BIG_ENDIAN);
        bb.putLong(guid.getUuid().getMostSignificantBits());
        bb.putLong(guid.getUuid().getLeastSignificantBits());
        return bb.array();
    }
}