/*
 * DWN - Desktop Window Manager
 * retoor <retoor@molodetz.nl>
 * Threading Integration with Main Event Loop
 * 
 * Integrates the threading framework with DWN's main X11 event loop
 * using select() for multiplexing.
 */

#include "threading.h"
#include "thread_workers.h"
#include "dwn.h"
#include "util.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>

/* ============================================================================
 * Integration State
 * ============================================================================ */

typedef struct {
    int original_xfd;
    int timer_fd;
    int event_bus_fd;
    ThreadPool *pool;
    bool initialized;
} ThreadingIntegration;

static ThreadingIntegration g_integration = {0};

/* ============================================================================
 * Initialization
 * ============================================================================ */

bool threading_integration_init(void)
{
    if (g_integration.initialized) return true;
    
    /* Initialize core threading */
    if (!threading_init()) {
        LOG_ERROR("Failed to initialize threading subsystem");
        return false;
    }
    
    /* Initialize workers */
    if (!thread_workers_init()) {
        LOG_ERROR("Failed to initialize worker threads");
        threading_shutdown();
        return false;
    }
    
    g_integration.pool = thread_pool_default();
    g_integration.timer_fd = deferred_get_poll_fd();
    g_integration.event_bus_fd = -1;  /* Would come from event bus */
    g_integration.initialized = true;
    
    LOG_INFO("Threading integration initialized");
    return true;
}

void threading_integration_shutdown(void)
{
    if (!g_integration.initialized) return;
    
    thread_workers_shutdown();
    threading_shutdown();
    
    g_integration.initialized = false;
    LOG_INFO("Threading integration shutdown");
}

/* ============================================================================
 * Select Integration
 * ============================================================================ */

/**
 * Prepare fd_set for select() call
 * Call this before select() to include threading fds
 */
void threading_integration_prepare_select(int xfd, fd_set *fds, int *max_fd)
{
    if (!g_integration.initialized) return;
    
    g_integration.original_xfd = xfd;
    
    /* Add timer fd */
    if (g_integration.timer_fd >= 0) {
        FD_SET(g_integration.timer_fd, fds);
        if (g_integration.timer_fd > *max_fd) {
            *max_fd = g_integration.timer_fd;
        }
    }
    
    /* Add event bus fd */
    if (g_integration.event_bus_fd >= 0) {
        FD_SET(g_integration.event_bus_fd, fds);
        if (g_integration.event_bus_fd > *max_fd) {
            *max_fd = g_integration.event_bus_fd;
        }
    }
}

/**
 * Process threading events after select() returns
 * Call this when select() indicates data available
 */
void threading_integration_process(fd_set *fds)
{
    if (!g_integration.initialized) return;
    
    /* Process timer events */
    if (g_integration.timer_fd >= 0 && FD_ISSET(g_integration.timer_fd, fds)) {
        deferred_process();
    }
    
    /* Process event bus */
    if (g_integration.event_bus_fd >= 0 && FD_ISSET(g_integration.event_bus_fd, fds)) {
        event_bus_process(event_bus_default());
    }
    
    /* Process async contexts */
    thread_workers_process_all();
}

/**
 * Non-blocking check for threading work
 * Call this periodically from main loop
 */
void threading_integration_poll(void)
{
    if (!g_integration.initialized) return;
    
    /* Process any pending async work */
    thread_workers_process_all();
}

/* ============================================================================
 * Convenience API for Main Loop
 * ============================================================================ */

/**
 * Run main loop iteration with integrated threading
 * This is an alternative to manual select() integration
 */
void threading_integration_run_iteration(int xfd, void (*handle_xevent)(void))
{
    if (!g_integration.initialized) {
        if (handle_xevent) handle_xevent();
        return;
    }
    
    fd_set fds;
    struct timeval tv;
    int max_fd = xfd;
    
    FD_ZERO(&fds);
    FD_SET(xfd, &fds);
    
    /* Add threading fds */
    threading_integration_prepare_select(xfd, &fds, &max_fd);
    
    /* Short timeout for responsive async processing */
    tv.tv_sec = 0;
    tv.tv_usec = 10000; /* 10ms */
    
    int ready = select(max_fd + 1, &fds, NULL, NULL, &tv);
    
    if (ready > 0) {
        /* Process X11 events */
        if (FD_ISSET(xfd, &fds)) {
            if (handle_xevent) handle_xevent();
        }
        
        /* Process threading events */
        threading_integration_process(&fds);
    } else {
        /* No events, just process pending async work */
        threading_integration_poll();
    }
}

/* ============================================================================
 * Stats Integration
 * ============================================================================ */

/**
 * Get thread pool statistics for display/debugging
 */
void threading_integration_get_stats(char *buf, size_t bufsize)
{
    if (!g_integration.initialized || !buf || bufsize == 0) return;
    
    ThreadPool *pool = g_integration.pool;
    
    uint32_t active = thread_pool_active_count(pool);
    uint32_t pending = thread_pool_pending_count(pool);
    
    snprintf(buf, bufsize, "Threads: %u active, %u pending tasks", 
             active, pending);
}

/* ============================================================================
 * Module-Specific Async Contexts
 * ============================================================================ */

/* Async contexts for different subsystems */
static AsyncContext *g_ai_context = NULL;
static AsyncContext *g_screenshot_context = NULL;
static AsyncContext *g_ocr_context = NULL;

bool threading_integration_init_module_contexts(void)
{
    if (!g_integration.initialized) return false;
    
    g_ai_context = async_context_create("ai");
    g_screenshot_context = async_context_create("screenshot");
    g_ocr_context = async_context_create("ocr");
    
    return (g_ai_context && g_screenshot_context && g_ocr_context);
}

void threading_integration_cleanup_module_contexts(void)
{
    if (g_ocr_context) {
        async_context_destroy(g_ocr_context);
        g_ocr_context = NULL;
    }
    if (g_screenshot_context) {
        async_context_destroy(g_screenshot_context);
        g_screenshot_context = NULL;
    }
    if (g_ai_context) {
        async_context_destroy(g_ai_context);
        g_ai_context = NULL;
    }
}

AsyncContext* threading_integration_get_ai_context(void)
{
    return g_ai_context;
}

AsyncContext* threading_integration_get_screenshot_context(void)
{
    return g_screenshot_context;
}

AsyncContext* threading_integration_get_ocr_context(void)
{
    return g_ocr_context;
}

/* ============================================================================
 * High-Level Task Submission Helpers
 * ============================================================================ */

/**
 * Submit AI work
 */
TaskHandle threading_integration_submit_ai(TaskFunc func, void *user_data)
{
    if (!g_ai_context) return NULL;
    return async_submit(g_ai_context, func, user_data, TASK_PRIORITY_NORMAL);
}

/**
 * Submit screenshot work
 */
TaskHandle threading_integration_submit_screenshot(TaskFunc func, void *user_data)
{
    if (!g_screenshot_context) return NULL;
    return async_submit(g_screenshot_context, func, user_data, TASK_PRIORITY_HIGH);
}

/**
 * Submit OCR work
 */
TaskHandle threading_integration_submit_ocr(TaskFunc func, void *user_data)
{
    if (!g_ocr_context) return NULL;
    return async_submit(g_ocr_context, func, user_data, TASK_PRIORITY_NORMAL);
}

/**
 * Submit UI-critical work (runs at highest priority)
 */
TaskHandle threading_integration_submit_ui(TaskFunc func, void *user_data)
{
    TaskHandle task = task_create(func, user_data, TASK_PRIORITY_CRITICAL);
    if (!task) return NULL;
    
    ThreadStatus status = thread_pool_submit(thread_pool_default(), task);
    if (status != THREAD_OK) {
        task_destroy(task);
        return NULL;
    }
    
    return task;
}

/**
 * Submit background work (runs at lowest priority)
 */
TaskHandle threading_integration_submit_background(TaskFunc func, void *user_data)
{
    TaskHandle task = task_create(func, user_data, TASK_PRIORITY_IDLE);
    if (!task) return NULL;
    
    ThreadStatus status = thread_pool_submit(thread_pool_default(), task);
    if (status != THREAD_OK) {
        task_destroy(task);
        return NULL;
    }
    
    return task;
}
