import java.lang.foreign.*;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import static java.lang.foreign.ValueLayout.*;

public class Main {

    public static void main(String[] arguments) throws Throwable {

        var linker = Linker.nativeLinker();
        var scope = SegmentScope.auto();
        var lookup = MethodHandles.lookup();

        var kernelLibrary = SymbolLookup.libraryLookup("Kernel32", scope);
        var userLibrary = SymbolLookup.libraryLookup("User32", scope);

        var enumWindowsSymbol = userLibrary.find("EnumWindows").orElseThrow();
        var enumWindowsDescriptor = FunctionDescriptor.of(JAVA_BOOLEAN, ADDRESS, ADDRESS);
        var enumWindowsHandle = linker.downcallHandle(enumWindowsSymbol, enumWindowsDescriptor);

        var getLastErrorSymbol = kernelLibrary.find("GetLastError").orElseThrow();
        var getLastErrorDescriptor = FunctionDescriptor.of(JAVA_INT);
        var getLastErrorHandle = linker.downcallHandle(getLastErrorSymbol, getLastErrorDescriptor);

        var procedureMethodType = MethodType.methodType(boolean.class, MemorySegment.class, MemorySegment.class);
        var procedureHandle = lookup.findStatic(Main.class, "procedure", procedureMethodType);
        var procedureDescriptor = FunctionDescriptor.of(JAVA_BOOLEAN, ADDRESS, ADDRESS);
        var procedureStub = linker.upcallStub(procedureHandle, procedureDescriptor, scope);

        // TO RESOLVE:
        // Thread.sleep(1500);

        var result = (boolean) enumWindowsHandle.invoke(procedureStub, MemorySegment.NULL);
        var lastError = (int) getLastErrorHandle.invoke();

        System.out.println("EnumWindows result: " + result);
        System.out.println("Last Error: " + lastError);

    }

    public static boolean procedure(MemorySegment windowHandle, MemorySegment parameter) {
        // CREATES ERROR (UNLESS THERE IS A SYNTHETIC DELAY):
        System.out.printf("windowHandle: %d\n", windowHandle.address());
        System.out.printf("parameter: %d\n", parameter.address());

        // ALTERNATIVELY DOES NOT CREATE ERROR (NO SYNTHETIC DELAY REQUIRED):
        // System.out.println("windowHandle: " + windowHandle.address());
        // System.out.println("parameter: " + parameter.address());
        return false;
    }
} 