/**
 * @file wow64_thunk.c
 * @brief WoW64 thunk layer for 32-bit Windows applications on 64-bit Linux
 *
 * MVGAL - Multi-Vendor GPU Aggregation Layer for Linux
 *
 * SPDX-License-Identifier: MIT
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#include "wow64.h"
#include "ntsync.h"

/* WoW64 translation tables and helpers */

/**
 * @brief Thunk context for 32/64-bit translation
 */
struct wow64_thunk_context {
    void *lib_handle;          /* Handle to the thunk library */
    int is_32bit;              /* Non-zero if target is 32-bit */
    uint32_t *thunk_table;     /* Translation function table */
    int ntsync_fd;             /* Fallback eventfd for NT sync */
};

/* WoW64 translation tables and helpers */

/**
 * @brief Thunk context for 32/64-bit translation
 */
struct wow64_thunk_context {
    void *lib_handle;          /* Handle to the thunk library */
    int is_32bit;              /* Non-zero if target is 32-bit */
    uint32_t *thunk_table;     /* Translation function table */
};

/* Global thunk state */
static struct wow64_thunk_context g_thunk_ctx;

/**
 * @brief Allocate shared memory for 32/64-bit interop
 * @param size Size of shared memory region
 * @return Pointer to shared memory, or NULL on failure
 */
void *wow64_alloc_shared_memory(size_t size) {
    void *ptr;
    
    ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (ptr == MAP_FAILED) {
        return NULL;
    }
    
    return ptr;
}

/**
 * @brief Free shared memory
 * @param ptr Pointer to shared memory
 * @param size Size of the region
 */
void wow64_free_shared_memory(void *ptr, size_t size) {
    munmap(ptr, size);
}

/**
 * @brief Thunk a 32-bit pointer to 64-bit
 * @param ptr32 32-bit pointer value
 * @return 64-bit pointer
 */
void *wow64_thunk_pointer(uint32_t ptr32) {
    /* In a real implementation, this would translate through a mapping table */
    return (void *)(uintptr_t)ptr32;
}

/**
 * @brief Thunk a 64-bit pointer to 32-bit
 * @param ptr 64-bit pointer
 * @return 32-bit pointer value
 */
uint32_t wow64_unthunk_pointer(const void *ptr) {
    uintptr_t addr = (uintptr_t)ptr;
    /* In a real implementation, this would validate the address is in range */
    return (uint32_t)(addr & 0xFFFFFFFFUL);
}

/**
 * @brief Initialize WoW64 thunk layer
 * @param is_32bit Target architecture flag
 * @return 0 on success, -1 on failure
 */
int wow64_init(int is_32bit) {
    memset(&g_thunk_ctx, 0, sizeof(g_thunk_ctx));
    g_thunk_ctx.is_32bit = is_32bit;
    
    /* Try to initialize kernel ntsync first */
    int ntsync_ret = ntsync_init();
    if (ntsync_ret == 0) {
        g_thunk_ctx.ntsync_fd = 0; /* Mark as kernel available */
    } else {
        /* Fall back to eventfd-based implementation */
        g_thunk_ctx.ntsync_fd = eventfd(0, EFD_CLOEXEC);
        if (g_thunk_ctx.ntsync_fd < 0) {
            g_thunk_ctx.ntsync_fd = -1; /* Will use syscall fallback */
        }
    }
    
    /* Load the thunk library if available */
    g_thunk_ctx.lib_handle = dlopen("libmvgal_thunk.so", RTLD_LAZY);
    if (!g_thunk_ctx.lib_handle) {
        /* Non-fatal - thunking can still work with basic translations */
    }
    
    return 0;
}

/**
 * @brief Cleanup WoW64 thunk layer
 */
void wow64_fini(void) {
    if (g_thunk_ctx.lib_handle) {
        dlclose(g_thunk_ctx.lib_handle);
        g_thunk_ctx.lib_handle = NULL;
    }
    
    /* Cleanup fallback eventfd */
    if (g_thunk_ctx.ntsync_fd > 0) {
        close(g_thunk_ctx.ntsync_fd);
        g_thunk_ctx.ntsync_fd = -1;
    }
    
    /* Cleanup kernel ntsync */
    ntsync_fini();
}

/**
 * @brief Call a 32-bit function from 64-bit context
 * @param func32 32-bit function pointer
 * @param args Arguments array
 * @param arg_count Number of arguments
 * @return Return value
 */
uint64_t wow64_call_32bit(uint32_t func32, uint64_t *args, int arg_count) {
    /* If we have kernel ntsync, use it for synchronization */
    if (g_thunk_ctx.ntsync_fd == 0) {
        /* Kernel ntsync available - functions would use that */
        /* This would typically involve calling into Wine via wine_ntsync_* */
    }
    
    /* This is a stub - real implementation would use vsyscall or emulator */
    /* For WoW64 support, this integrates with Wine's call wrapper */
    (void)func32;
    (void)args;
    (void)arg_count;
    
    return 0;
}

/**
 * @brief Get thunk context
 * @return Pointer to thunk context
 */
struct wow64_thunk_context *wow64_get_context(void) {
    return &g_thunk_ctx;
}