#define _XOPEN_SOURCE 500
/**
 * GTK2 Media Player - Plugin Manager Implementation
 */

#include "plugin_manager.h"
#include "ui.h"
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>

#define MAX_PLUGINS 64
#define PLUGINS_SUBDIR "gtk2-media-player/plugins"

struct PluginManager {
    AppUI *ui;
    char *plugins_dir;
    char *last_plugin_dir;
    LoadedPlugin *plugins[MAX_PLUGINS];
    int plugin_count;
    GtkWidget *plugins_menu;
    GList *registered_menu_items;
    PluginAPI api;
};

/* Forward declarations for static API functions */
static PluginManager *g_pm = NULL;  /* Global for API callbacks */

static void api_play(void);
static void api_pause(void);
static void api_stop(void);
static void api_toggle_pause(void);
static void api_seek(double seconds);
static void api_seek_absolute(double position);
static double api_get_position(void);
static double api_get_duration(void);
static double api_get_volume(void);
static gboolean api_is_paused(void);
static gboolean api_is_playing(void);
static char* api_get_current_file(void);
static char* api_get_media_title(void);
static void api_take_screenshot(void);
static void api_take_screenshot_to_file(const char *path);
static void api_take_screenshot_to_file(const char *path);
static GtkWindow* api_get_main_window(void);
static void api_show_info(const char *title, const char *message);
static void api_show_warning(const char *title, const char *message);
static void api_show_error(const char *title, const char *message);
static void api_register_menu_item(GtkWidget *item);
static void api_register_menu_item(GtkWidget *item);
static void api_unregister_menu_item(GtkWidget *item);
static void api_set_video_area_visible(gboolean visible);
static void api_set_window_size(int width, int height);
static void api_execute_mpv_command(const char **args);

/* Player callback storage */
static struct {
    void (*play)(void);
    void (*pause)(void);
    void (*stop)(void);
    void (*toggle_pause)(void);
    void (*seek)(double);
    void (*seek_absolute)(double);
    double (*get_position)(void);
    double (*get_duration)(void);
    double (*get_volume)(void);
    gboolean (*is_paused)(void);
    gboolean (*is_playing)(void);
    char* (*get_current_file)(void);
    char* (*get_media_title)(void);
    void (*take_screenshot)(void);
    void (*take_screenshot_to_file)(const char*);
} player_cbs = {0};

/* ============================================================================
 * Plugin Manager Lifecycle
 * ============================================================================ */

PluginManager* plugin_manager_new(AppUI *ui)
{
    PluginManager *pm = g_malloc0(sizeof(PluginManager));
    pm->ui = ui;
    pm->plugin_count = 0;
    pm->registered_menu_items = NULL;
    
    /* Build plugins directory path */
    const char *config_dir = g_get_user_config_dir();
    pm->plugins_dir = g_build_filename(config_dir, PLUGINS_SUBDIR, NULL);
    
    /* Create directory if it doesn't exist */
    g_mkdir_with_parents(pm->plugins_dir, 0755);
    
    /* Initialize API structure */
    pm->api.play = api_play;
    pm->api.pause = api_pause;
    pm->api.stop = api_stop;
    pm->api.toggle_pause = api_toggle_pause;
    pm->api.seek = api_seek;
    pm->api.seek_absolute = api_seek_absolute;
    pm->api.get_position = api_get_position;
    pm->api.get_duration = api_get_duration;
    pm->api.get_volume = api_get_volume;
    pm->api.is_paused = api_is_paused;
    pm->api.is_playing = api_is_playing;
    pm->api.get_current_file = api_get_current_file;
    pm->api.get_media_title = api_get_media_title;
    pm->api.take_screenshot = api_take_screenshot;
    pm->api.take_screenshot_to_file = api_take_screenshot_to_file;
    pm->api.get_main_window = api_get_main_window;
    pm->api.show_info = api_show_info;
    pm->api.show_warning = api_show_warning;
    pm->api.show_error = api_show_error;
    pm->api.register_menu_item = api_register_menu_item;
    pm->api.unregister_menu_item = api_unregister_menu_item;
    pm->api.set_video_area_visible = api_set_video_area_visible;
    pm->api.set_window_size = api_set_window_size;
    pm->api.execute_mpv_command = api_execute_mpv_command;
    
    g_pm = pm;
    
    printf("Plugin manager initialized. Plugins directory: %s\n", pm->plugins_dir);
    return pm;
}

void plugin_manager_destroy(PluginManager *pm)
{
    if (!pm) return;
    
    /* Shutdown and unload all plugins */
    for (int i = 0; i < pm->plugin_count; i++) {
        LoadedPlugin *p = pm->plugins[i];
        if (p) {
            if (p->enabled && p->shutdown) {
                printf("Shutting down plugin: %s\n", p->info.name);
                p->shutdown();
            }
            if (p->handle) {
                dlclose(p->handle);
            }
            g_free(p->id);
            g_free(p->path);
            g_free(p);
        }
    }
    
    g_list_free(pm->registered_menu_items);
    g_free(pm->plugins_dir);
    g_free(pm);
    g_pm = NULL;
}

void plugin_manager_set_player_callbacks(PluginManager *pm,
    void (*play)(void),
    void (*pause)(void),
    void (*stop)(void),
    void (*toggle_pause)(void),
    void (*seek)(double),
    void (*seek_absolute)(double),
    double (*get_position)(void),
    double (*get_duration)(void),
    double (*get_volume)(void),
    gboolean (*is_paused)(void),
    gboolean (*is_playing)(void),
    char* (*get_current_file)(void),
    char* (*get_media_title)(void),
    void (*take_screenshot)(void),
    void (*take_screenshot_to_file)(const char*))
{
    (void)pm;
    player_cbs.play = play;
    player_cbs.pause = pause;
    player_cbs.stop = stop;
    player_cbs.toggle_pause = toggle_pause;
    player_cbs.seek = seek;
    player_cbs.seek_absolute = seek_absolute;
    player_cbs.get_position = get_position;
    player_cbs.get_duration = get_duration;
    player_cbs.get_volume = get_volume;
    player_cbs.is_paused = is_paused;
    player_cbs.is_playing = is_playing;
    player_cbs.get_current_file = get_current_file;
    player_cbs.get_media_title = get_media_title;
    player_cbs.take_screenshot = take_screenshot;
    player_cbs.take_screenshot_to_file = take_screenshot_to_file;
}

/* ============================================================================
 * Plugin Loading
 * ============================================================================ */

static LoadedPlugin* load_plugin(PluginManager *pm, const char *plugin_dir, const char *plugin_id)
{
    /* Find .so file in plugin directory */
    DIR *dir = opendir(plugin_dir);
    if (!dir) {
        fprintf(stderr, "Cannot open plugin directory: %s\n", plugin_dir);
        return NULL;
    }
    
    char *so_path = NULL;
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        size_t len = strlen(entry->d_name);
        if (len > 3 && strcmp(entry->d_name + len - 3, ".so") == 0) {
            so_path = g_build_filename(plugin_dir, entry->d_name, NULL);
            break;
        }
    }
    closedir(dir);
    
    if (!so_path) {
        fprintf(stderr, "No .so file found in: %s\n", plugin_dir);
        return NULL;
    }
    
    /* Load the shared library */
    char *abs_so = realpath(so_path, NULL);
    printf("Attempting to load plugin library: %s\n", abs_so ? abs_so : so_path);
    
    void *handle = dlopen(so_path, RTLD_NOW);
    if (!handle) {
        fprintf(stderr, "Failed to load plugin %s: %s\n", so_path, dlerror());
        
        /* Debug: attempt to see what dependencies are missing */
        printf("DEBUG: Dependency check for %s:\n", so_path);
        char *ldd_cmd = g_strdup_printf("ldd '%s'", so_path);
        system(ldd_cmd);
        g_free(ldd_cmd);
        
        g_free(so_path);
        if (abs_so) free(abs_so);
        return NULL;
    }
    if (abs_so) free(abs_so);
    
    /* Load required symbols */
    PluginGetInfoFunc get_info = (PluginGetInfoFunc)dlsym(handle, PLUGIN_EXPORT_GET_INFO);
    PluginInitFunc init = (PluginInitFunc)dlsym(handle, PLUGIN_EXPORT_INIT);
    PluginShutdownFunc shutdown = (PluginShutdownFunc)dlsym(handle, PLUGIN_EXPORT_SHUTDOWN);
    
    if (!get_info || !init || !shutdown) {
        fprintf(stderr, "Plugin %s missing required exports\n", so_path);
        dlclose(handle);
        g_free(so_path);
        return NULL;
    }
    
    /* Get plugin info */
    const PluginInfo *info = get_info();
    if (!info) {
        fprintf(stderr, "Plugin %s returned NULL info\n", so_path);
        dlclose(handle);
        g_free(so_path);
        return NULL;
    }
    
    /* Check API version */
    if (info->api_version != PLUGIN_API_VERSION) {
        fprintf(stderr, "Plugin %s API version mismatch (got %d, expected %d)\n",
                info->name, info->api_version, PLUGIN_API_VERSION);
        dlclose(handle);
        g_free(so_path);
        return NULL;
    }
    
    /* Create plugin instance */
    LoadedPlugin *p = g_malloc0(sizeof(LoadedPlugin));
    p->id = g_strdup(plugin_id);
    p->path = so_path;
    p->handle = handle;
    p->info = *info;
    p->get_info = get_info;
    p->init = init;
    p->shutdown = shutdown;
    
    /* Load optional symbols */
    p->get_menu_item = (PluginGetMenuFunc)dlsym(handle, PLUGIN_EXPORT_GET_MENU);
    p->on_event = (PluginOnEventFunc)dlsym(handle, PLUGIN_EXPORT_ON_EVENT);
    p->configure = (PluginConfigureFunc)dlsym(handle, PLUGIN_EXPORT_CONFIGURE);
    p->about = (PluginAboutFunc)dlsym(handle, PLUGIN_EXPORT_ABOUT);
    
    /* Initialize the plugin */
    if (init(&pm->api) != 0) {
        fprintf(stderr, "Plugin %s init failed\n", info->name);
        dlclose(handle);
        g_free(p->id);
        g_free(p->path);
        g_free(p);
        return NULL;
    }
    
    p->enabled = TRUE;
    
    /* Get menu item if available */
    if (p->get_menu_item) {
        p->menu_item = p->get_menu_item();
        p->has_menu = (p->menu_item != NULL);
    }
    
    printf("Plugin loaded successfully: %s v%s\n", info->name, info->version);
    return p;
}

int plugin_manager_load_all(PluginManager *pm)
{
    if (!pm) return 0;
    
    DIR *dir = opendir(pm->plugins_dir);
    if (!dir) {
        printf("Plugins directory does not exist or is empty: %s\n", pm->plugins_dir);
        return 0;
    }
    
    int loaded = 0;
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL && pm->plugin_count < MAX_PLUGINS) {
        if (entry->d_name[0] == '.') continue;
        
        char *plugin_path = g_build_filename(pm->plugins_dir, entry->d_name, NULL);
        
        struct stat st;
        if (stat(plugin_path, &st) == 0 && S_ISDIR(st.st_mode)) {
            LoadedPlugin *p = load_plugin(pm, plugin_path, entry->d_name);
            if (p) {
                pm->plugins[pm->plugin_count++] = p;
                loaded++;
            }
        }
        
        g_free(plugin_path);
    }
    closedir(dir);
    
    printf("Loaded %d plugin(s)\n", loaded);
    return loaded;
}

/* ============================================================================
 * Plugin Installation
 * ============================================================================ */

gboolean plugin_manager_install_zip(PluginManager *pm, const char *zip_path)
{
    if (!pm || !zip_path) return FALSE;
    
    /* Extract zip to temp directory first to check contents */
    char *temp_dir = g_build_filename(g_get_tmp_dir(), "plugin_install_XXXXXX", NULL);
    char *actual_temp = g_mkdtemp(temp_dir);
    if (!actual_temp) {
        fprintf(stderr, "Failed to create temp directory\n");
        g_free(temp_dir);
        return FALSE;
    }
    
    /* Run unzip command */
    char *cmd = g_strdup_printf("unzip -q '%s' -d '%s'", zip_path, actual_temp);
    int ret = system(cmd);
    g_free(cmd);
    
    if (ret != 0) {
        fprintf(stderr, "Failed to extract zip file\n");
        /* Clean up temp dir */
        cmd = g_strdup_printf("rm -rf '%s'", actual_temp);
        system(cmd);
        g_free(cmd);
        g_free(temp_dir);
        return FALSE;
    }
    
    /* Find the plugin directory (first subdirectory) */
    DIR *dir = opendir(actual_temp);
    if (!dir) {
        g_free(temp_dir);
        return FALSE;
    }
    
    char *plugin_name = NULL;
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_name[0] == '.') continue;
        
        char *path = g_build_filename(actual_temp, entry->d_name, NULL);
        struct stat st;
        if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
            plugin_name = g_strdup(entry->d_name);
            g_free(path);
            break;
        }
        g_free(path);
    }
    closedir(dir);
    
    if (!plugin_name) {
        /* Maybe files are at root level, use zip name */
        char *base = g_path_get_basename(zip_path);
        /* Remove .zip extension */
        char *dot = strrchr(base, '.');
        if (dot) *dot = '\0';
        plugin_name = base;
    }
    
    /* Move to plugins directory */
    char *dest = g_build_filename(pm->plugins_dir, plugin_name, NULL);
    
    /* Remove existing if present */
    if (g_file_test(dest, G_FILE_TEST_EXISTS)) {
        cmd = g_strdup_printf("rm -rf '%s'", dest);
        system(cmd);
        g_free(cmd);
    }
    
    /* Check if we need to move subdirectory or temp dir itself */
    char *src = g_build_filename(actual_temp, plugin_name, NULL);
    if (!g_file_test(src, G_FILE_TEST_IS_DIR)) {
        g_free(src);
        src = g_strdup(actual_temp);
    }
    
    cmd = g_strdup_printf("mv '%s' '%s'", src, dest);
    ret = system(cmd);
    g_free(cmd);
    g_free(src);
    
    /* Clean up temp dir */
    cmd = g_strdup_printf("rm -rf '%s'", actual_temp);
    system(cmd);
    g_free(cmd);
    g_free(temp_dir);
    
    if (ret != 0) {
        fprintf(stderr, "Failed to install plugin to %s\n", dest);
        g_free(dest);
        g_free(plugin_name);
        return FALSE;
    }
    
    /* Check if plugin is already loaded (e.g., from startup) */
    for (int i = 0; i < pm->plugin_count; i++) {
        if (pm->plugins[i] && strcmp(pm->plugins[i]->id, plugin_name) == 0) {
            printf("Plugin already loaded: %s\n", plugin_name);
            g_free(dest);
            g_free(plugin_name);
            return TRUE;  /* Already loaded, consider it a success */
        }
    }
    
    /* Load the newly installed plugin */
    if (pm->plugin_count < MAX_PLUGINS) {
        LoadedPlugin *p = load_plugin(pm, dest, plugin_name);
        if (p) {
            pm->plugins[pm->plugin_count++] = p;
            printf("Successfully installed plugin: %s\n", p->info.name);
            g_free(dest);
            g_free(plugin_name);
            return TRUE;
        } else {
            fprintf(stderr, "Failed to load plugin after installation: %s\n", plugin_name);
        }
    }
    
    g_free(dest);
    g_free(plugin_name);
    return FALSE;
}

gboolean plugin_manager_uninstall(PluginManager *pm, const char *plugin_id)
{
    if (!pm || !plugin_id) return FALSE;
    
    /* Find the plugin */
    int idx = -1;
    for (int i = 0; i < pm->plugin_count; i++) {
        if (pm->plugins[i] && strcmp(pm->plugins[i]->id, plugin_id) == 0) {
            idx = i;
            break;
        }
    }
    
    if (idx < 0) {
        fprintf(stderr, "Plugin not found: %s\n", plugin_id);
        return FALSE;
    }
    
    LoadedPlugin *p = pm->plugins[idx];
    
    /* Shutdown plugin */
    if (p->enabled && p->shutdown) {
        p->shutdown();
    }
    
    /* Close library */
    if (p->handle) {
        dlclose(p->handle);
    }
    
    /* Remove directory */
    char *plugin_dir = g_build_filename(pm->plugins_dir, plugin_id, NULL);
    char *cmd = g_strdup_printf("rm -rf '%s'", plugin_dir);
    system(cmd);
    g_free(cmd);
    g_free(plugin_dir);
    
    /* Remove from array */
    g_free(p->id);
    g_free(p->path);
    g_free(p);
    
    for (int i = idx; i < pm->plugin_count - 1; i++) {
        pm->plugins[i] = pm->plugins[i + 1];
    }
    pm->plugin_count--;
    
    return TRUE;
}

/* ============================================================================
 * Plugin Menu
 * ============================================================================ */

LoadedPlugin** plugin_manager_get_list(PluginManager *pm, int *count)
{
    if (!pm) {
        if (count) *count = 0;
        return NULL;
    }
    if (count) *count = pm->plugin_count;
    return pm->plugins;
}

static void on_install_plugin(GtkMenuItem *item, gpointer data)
{
    (void)item;
    PluginManager *pm = (PluginManager*)data;
    
    GtkWidget *dialog = gtk_file_chooser_dialog_new(
        "Install Plugin",
        GTK_WINDOW(ui_get_window(pm->ui)),
        GTK_FILE_CHOOSER_ACTION_OPEN,
        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
        NULL);
    
    GtkFileFilter *filter = gtk_file_filter_new();
    gtk_file_filter_set_name(filter, "Plugin Archives (*.zip)");
    gtk_file_filter_add_pattern(filter, "*.zip");
    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
    
    if (pm->last_plugin_dir) {
        gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), pm->last_plugin_dir);
    }
    
    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
        char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
        
        /* Save the directory for next time */
        g_free(pm->last_plugin_dir);
        pm->last_plugin_dir = g_path_get_dirname(filename);
        
        if (plugin_manager_install_zip(pm, filename)) {
            GtkWidget *msg = gtk_message_dialog_new(
                GTK_WINDOW(ui_get_window(pm->ui)),
                GTK_DIALOG_MODAL,
                GTK_MESSAGE_QUESTION,
                GTK_BUTTONS_YES_NO,
                "Plugin installed successfully!\n\nRestart the application now to use the new plugin?");
            
            gtk_window_set_title(GTK_WINDOW(msg), "Restart Required");
            
            if (gtk_dialog_run(GTK_DIALOG(msg)) == GTK_RESPONSE_YES) {
                ui_restart(pm->ui);
            }
            gtk_widget_destroy(msg);
        } else {
            GtkWidget *msg = gtk_message_dialog_new(
                GTK_WINDOW(ui_get_window(pm->ui)),
                GTK_DIALOG_MODAL,
                GTK_MESSAGE_ERROR,
                GTK_BUTTONS_OK,
                "Failed to install plugin.");
            gtk_dialog_run(GTK_DIALOG(msg));
            gtk_widget_destroy(msg);
        }
        g_free(filename);
    }
    
    gtk_widget_destroy(dialog);
}

GtkWidget* plugin_manager_get_menu(PluginManager *pm)
{
    if (!pm) return NULL;
    
    GtkWidget *menu = gtk_menu_new();
    
    /* Add plugin menu items */
    for (int i = 0; i < pm->plugin_count; i++) {
        LoadedPlugin *p = pm->plugins[i];
        if (p && p->has_menu && p->menu_item) {
            gtk_menu_shell_append(GTK_MENU_SHELL(menu), p->menu_item);
        }
    }
    
    /* Add registered menu items */
    for (GList *l = pm->registered_menu_items; l != NULL; l = l->next) {
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(l->data));
    }
    
    /* Separator if we have plugins */
    if (pm->plugin_count > 0 || pm->registered_menu_items != NULL) {
        GtkWidget *sep = gtk_separator_menu_item_new();
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
    }
    
    GtkWidget *install_item = gtk_menu_item_new_with_label("Install Plugin...");
    g_signal_connect(install_item, "activate", G_CALLBACK(on_install_plugin), pm);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), install_item);
    
    GtkWidget *manage_scripts_item = gtk_menu_item_new_with_label("Manage Scripts...");
    g_signal_connect_swapped(manage_scripts_item, "activate", G_CALLBACK(ui_show_script_manager), pm->ui);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), manage_scripts_item);
    
    GtkWidget *scripts_item = gtk_menu_item_new_with_label("Open Scripts Folder...");
    g_signal_connect_swapped(scripts_item, "activate", G_CALLBACK(ui_open_scripts_folder), pm->ui);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), scripts_item);
    
    /* Manage plugins - Removed as per user request (moved to preferences) */
    /*
    GtkWidget *manage_item = gtk_menu_item_new_with_label("Manage Plugins...");
    g_signal_connect_swapped(manage_item, "activate", G_CALLBACK(plugin_manager_show_dialog), pm);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), manage_item);
    */
    
    gtk_widget_show_all(menu);
    pm->plugins_menu = menu;
    
    return menu;
}

void plugin_manager_register_menu_item(PluginManager *pm, GtkWidget *item)
{
    if (!pm || !item) return;
    pm->registered_menu_items = g_list_append(pm->registered_menu_items, item);
}

void plugin_manager_unregister_menu_item(PluginManager *pm, GtkWidget *item)
{
    if (!pm || !item) return;
    pm->registered_menu_items = g_list_remove(pm->registered_menu_items, item);
}

/* ============================================================================
 * Plugin Events
 * ============================================================================ */

void plugin_manager_broadcast_event(PluginManager *pm, PluginEventType event, void *data)
{
    if (!pm) return;
    
    for (int i = 0; i < pm->plugin_count; i++) {
        LoadedPlugin *p = pm->plugins[i];
        if (p && p->enabled && p->on_event) {
            p->on_event(event, data);
        }
    }
}

/* ============================================================================
 * Manage Plugins Dialog
 * ============================================================================ */

static void on_configure_clicked(GtkButton *button, gpointer data)
{
    (void)data;
    LoadedPlugin *p = g_object_get_data(G_OBJECT(button), "plugin");
    if (p && p->enabled && p->configure) {
        p->configure();
    }
}

static void on_about_clicked(GtkButton *button, gpointer data)
{
    (void)data;
    LoadedPlugin *p = g_object_get_data(G_OBJECT(button), "plugin");
    if (p && p->enabled && p->about) {
        p->about();
    }
}

static void on_uninstall_clicked(GtkButton *button, gpointer data)
{
    GtkWidget *frame = GTK_WIDGET(data);
    LoadedPlugin *p = g_object_get_data(G_OBJECT(button), "plugin");
    PluginManager *pm = g_object_get_data(G_OBJECT(button), "pm"); // Need to store PM too
    
    if (!p || !pm) return;
    
    GtkWidget *dialog = gtk_message_dialog_new(
        NULL,
        GTK_DIALOG_MODAL,
        GTK_MESSAGE_QUESTION,
        GTK_BUTTONS_YES_NO,
        "Uninstall plugin '%s'?\nThis cannot be undone.", p->info.name);
    
    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
        gtk_widget_destroy(dialog);
        
        char *name = g_strdup(p->info.name);
        if (plugin_manager_uninstall(pm, p->id)) {
            /* Destroy the UI row */
            gtk_widget_destroy(frame);
            
            GtkWidget *msg = gtk_message_dialog_new(
                NULL,
                GTK_DIALOG_MODAL,
                GTK_MESSAGE_INFO,
                GTK_BUTTONS_OK,
                "Plugin '%s' uninstalled.\nRestart application to fully clear resources.", name);
            gtk_dialog_run(GTK_DIALOG(msg));
            gtk_widget_destroy(msg);
        } else {
             GtkWidget *msg = gtk_message_dialog_new(
                NULL,
                GTK_DIALOG_MODAL,
                GTK_MESSAGE_ERROR,
                GTK_BUTTONS_OK,
                "Failed to uninstall plugin '%s'.", name);
            gtk_dialog_run(GTK_DIALOG(msg));
            gtk_widget_destroy(msg);
        }
        g_free(name);
    } else {
        gtk_widget_destroy(dialog);
    }
}

GtkWidget* plugin_manager_create_config_widget(PluginManager *pm)
{
    if (!pm) return gtk_label_new("Plugin manager not initialized");
    
    GtkWidget *vbox = gtk_vbox_new(FALSE, 10);
    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
    
    /* Top Toolbar Area */
    GtkWidget *toolbar_hbox = gtk_hbox_new(FALSE, 10);
    
    GtkWidget *install_btn = gtk_button_new_with_mnemonic("_Install Plugin from ZIP...");
    GtkWidget *install_icon = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
    gtk_button_set_image(GTK_BUTTON(install_btn), install_icon);
    g_signal_connect(install_btn, "clicked", G_CALLBACK(on_install_plugin), pm);
    gtk_box_pack_start(GTK_BOX(toolbar_hbox), install_btn, FALSE, FALSE, 0);
    
    /* Search/Info label */
    char *dir_text = g_strdup_printf("<small>Plugins dir: %s</small>", pm->plugins_dir);
    GtkWidget *dir_label = gtk_label_new(NULL);
    gtk_label_set_markup(GTK_LABEL(dir_label), dir_text);
    gtk_label_set_ellipsize(GTK_LABEL(dir_label), PANGO_ELLIPSIZE_END);
    gtk_misc_set_alignment(GTK_MISC(dir_label), 1.0, 0.5);
    gtk_box_pack_end(GTK_BOX(toolbar_hbox), dir_label, TRUE, TRUE, 0);
    g_free(dir_text);
    
    gtk_box_pack_start(GTK_BOX(vbox), toolbar_hbox, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(vbox), gtk_hseparator_new(), FALSE, FALSE, 0);
    
    GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_NONE);
    
    GtkWidget *list_vbox = gtk_vbox_new(FALSE, 8);
    
    if (pm->plugin_count == 0) {
        GtkWidget *empty_label = gtk_label_new("No plugins installed.");
        gtk_widget_modify_fg(empty_label, GTK_STATE_NORMAL, &(GdkColor){0, 0x8888, 0x8888, 0x8888});
        gtk_box_pack_start(GTK_BOX(list_vbox), empty_label, TRUE, TRUE, 30);
    } else {
        for (int i = 0; i < pm->plugin_count; i++) {
            LoadedPlugin *p = pm->plugins[i];
            if (!p) continue;
            
            GtkWidget *frame = gtk_frame_new(NULL);
            gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
            
            GtkWidget *row_hbox = gtk_hbox_new(FALSE, 12);
            gtk_container_set_border_width(GTK_CONTAINER(row_hbox), 12);
            
            /* Left side: Info */
            GtkWidget *info_vbox = gtk_vbox_new(FALSE, 4);
            
            char *name_markup = g_strdup_printf("<span size='large' weight='bold'>%s</span> <span color='#888'>v%s</span>", 
                                                        p->info.name, p->info.version);
            GtkWidget *name_label = gtk_label_new(NULL);
            gtk_label_set_markup(GTK_LABEL(name_label), name_markup);
            gtk_misc_set_alignment(GTK_MISC(name_label), 0, 0.5);
            g_free(name_markup);
            
            GtkWidget *desc_label = gtk_label_new(p->info.description);
            gtk_misc_set_alignment(GTK_MISC(desc_label), 0, 0.5);
            gtk_label_set_line_wrap(GTK_LABEL(desc_label), TRUE);
            gtk_label_set_max_width_chars(GTK_LABEL(desc_label), 50);
            
            char *author_markup = g_strdup_printf("<span size='small' color='#666'>by %s</span>", p->info.author);
            GtkWidget *author_label = gtk_label_new(NULL);
            gtk_label_set_markup(GTK_LABEL(author_label), author_markup);
            gtk_misc_set_alignment(GTK_MISC(author_label), 0, 0.5);
            g_free(author_markup);
            
            gtk_box_pack_start(GTK_BOX(info_vbox), name_label, FALSE, FALSE, 0);
            gtk_box_pack_start(GTK_BOX(info_vbox), desc_label, FALSE, FALSE, 2);
            gtk_box_pack_start(GTK_BOX(info_vbox), author_label, FALSE, FALSE, 0);
            
            /* Right side: Actions */
            GtkWidget *actions_vbox = gtk_vbox_new(FALSE, 4);
            
            /* Put Configure/About in a small grid or hbox? 
               Actually, a column of buttons on the right works well if they have uniform width. */
            
            if (p->configure) {
                GtkWidget *config_btn = gtk_button_new_with_label("Configure");
                g_object_set_data(G_OBJECT(config_btn), "plugin", p);
                g_signal_connect(config_btn, "clicked", G_CALLBACK(on_configure_clicked), NULL);
                gtk_box_pack_start(GTK_BOX(actions_vbox), config_btn, FALSE, FALSE, 0);
            }
            
            if (p->about) {
                GtkWidget *about_btn = gtk_button_new_with_label("About");
                g_object_set_data(G_OBJECT(about_btn), "plugin", p);
                g_signal_connect(about_btn, "clicked", G_CALLBACK(on_about_clicked), NULL);
                gtk_box_pack_start(GTK_BOX(actions_vbox), about_btn, FALSE, FALSE, 0);
            }
            
            /* Separator if we had configure/about */
            if (p->configure || p->about) {
                GtkWidget *spacer = gtk_vbox_new(FALSE, 0);
                gtk_widget_set_size_request(spacer, -1, 4);
                gtk_box_pack_start(GTK_BOX(actions_vbox), spacer, FALSE, FALSE, 0);
            }
            
            GtkWidget *uninstall_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
            gtk_button_set_label(GTK_BUTTON(uninstall_btn), "Uninstall");
            g_object_set_data(G_OBJECT(uninstall_btn), "plugin", p);
            g_object_set_data(G_OBJECT(uninstall_btn), "pm", pm);
            g_signal_connect(uninstall_btn, "clicked", G_CALLBACK(on_uninstall_clicked), frame);
            gtk_box_pack_start(GTK_BOX(actions_vbox), uninstall_btn, FALSE, FALSE, 0);
            
            /* Make all buttons in the actions_vbox the same width */
            GtkSizeGroup *sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
            if (p->configure) gtk_size_group_add_widget(sg, g_list_last(gtk_container_get_children(GTK_CONTAINER(actions_vbox)))->data); // Fix this later
            /* Actually it's easier to just iterate the vbox children */
            GList *btns = gtk_container_get_children(GTK_CONTAINER(actions_vbox));
            for (GList *l = btns; l != NULL; l = l->next) {
                if (GTK_IS_BUTTON(l->data)) gtk_size_group_add_widget(sg, GTK_WIDGET(l->data));
            }
            g_list_free(btns);
            g_object_unref(sg);

            gtk_box_pack_start(GTK_BOX(row_hbox), info_vbox, TRUE, TRUE, 0);
            gtk_box_pack_end(GTK_BOX(row_hbox), actions_vbox, FALSE, FALSE, 0);
            
            gtk_container_add(GTK_CONTAINER(frame), row_hbox);
            gtk_box_pack_start(GTK_BOX(list_vbox), frame, FALSE, FALSE, 0);
        }
    }
    
    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), list_vbox);
    gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
    
    return vbox;
}

void plugin_manager_show_dialog(PluginManager *pm)
{
    if (!pm) return;
    
    GtkWidget *dialog = gtk_dialog_new_with_buttons(
        "Manage Plugins",
        GTK_WINDOW(ui_get_window(pm->ui)),
        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
        GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
        NULL);
    
    gtk_window_set_default_size(GTK_WINDOW(dialog), 450, 400);
    
    GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
    GtkWidget *config_widget = plugin_manager_create_config_widget(pm);
    gtk_box_pack_start(GTK_BOX(content), config_widget, TRUE, TRUE, 0);
    
    gtk_widget_show_all(dialog);
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
}

const char* plugin_manager_get_plugins_dir(PluginManager *pm)
{
    return pm ? pm->plugins_dir : NULL;
}

/* ============================================================================
 * API Implementation (callbacks to application)
 * ============================================================================ */

static void api_play(void) {
    if (player_cbs.play) player_cbs.play();
}

static void api_pause(void) {
    if (player_cbs.pause) player_cbs.pause();
}

static void api_stop(void) {
    if (player_cbs.stop) player_cbs.stop();
}

static void api_toggle_pause(void) {
    if (player_cbs.toggle_pause) player_cbs.toggle_pause();
}

static void api_seek(double seconds) {
    if (player_cbs.seek) player_cbs.seek(seconds);
}

static void api_seek_absolute(double position) {
    if (player_cbs.seek_absolute) player_cbs.seek_absolute(position);
}

static double api_get_position(void) {
    return player_cbs.get_position ? player_cbs.get_position() : 0.0;
}

static double api_get_duration(void) {
    return player_cbs.get_duration ? player_cbs.get_duration() : 0.0;
}

static double api_get_volume(void) {
    return player_cbs.get_volume ? player_cbs.get_volume() : 100.0;
}

static gboolean api_is_paused(void) {
    return player_cbs.is_paused ? player_cbs.is_paused() : TRUE;
}

static gboolean api_is_playing(void) {
    return player_cbs.is_playing ? player_cbs.is_playing() : FALSE;
}

static char* api_get_current_file(void) {
    return player_cbs.get_current_file ? player_cbs.get_current_file() : NULL;
}

static char* api_get_media_title(void) {
    return player_cbs.get_media_title ? player_cbs.get_media_title() : NULL;
}

static void api_take_screenshot(void) {
    if (player_cbs.take_screenshot) player_cbs.take_screenshot();
}

static void api_take_screenshot_to_file(const char *path) {
    if (player_cbs.take_screenshot_to_file) player_cbs.take_screenshot_to_file(path);
}

static GtkWindow* api_get_main_window(void) {
    if (!g_pm || !g_pm->ui) return NULL;
    return GTK_WINDOW(ui_get_window(g_pm->ui));
}

static void api_show_info(const char *title, const char *message) {
    if (!g_pm || !g_pm->ui) return;
    GtkWindow *window = GTK_WINDOW(ui_get_window(g_pm->ui));
    GtkWidget *dialog = gtk_message_dialog_new(
        window, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
        "%s", message);
    gtk_window_set_title(GTK_WINDOW(dialog), title);
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
}

static void api_show_warning(const char *title, const char *message) {
    if (!g_pm || !g_pm->ui) return;
    GtkWindow *window = GTK_WINDOW(ui_get_window(g_pm->ui));
    GtkWidget *dialog = gtk_message_dialog_new(
        window, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
        "%s", message);
    gtk_window_set_title(GTK_WINDOW(dialog), title);
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
}

static void api_show_error(const char *title, const char *message) {
    if (!g_pm || !g_pm->ui) return;
    GtkWindow *window = GTK_WINDOW(ui_get_window(g_pm->ui));
    GtkWidget *dialog = gtk_message_dialog_new(
        window, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
        "%s", message);
    gtk_window_set_title(GTK_WINDOW(dialog), title);
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
}


static void api_register_menu_item(GtkWidget *item) {
    if (g_pm) plugin_manager_register_menu_item(g_pm, item);
}

static void api_unregister_menu_item(GtkWidget *item) {
    if (g_pm) plugin_manager_unregister_menu_item(g_pm, item);
}

static void api_set_video_area_visible(gboolean visible) {
    if (!g_pm || !g_pm->ui) return;
    ui_set_video_area_visible(g_pm->ui, visible);
}

static void api_set_window_size(int width, int height) {
    if (!g_pm || !g_pm->ui) return;
    ui_set_window_size(g_pm->ui, width, height);
}

static void api_execute_mpv_command(const char **args) {
    if (!g_pm || !g_pm->ui) return;
    Player *player = ui_get_player(g_pm->ui);
    if (player) {
        mpv_handle *mpv = player_get_mpv_handle(player);
        if (mpv) {
            mpv_command_async(mpv, 0, args);
        }
    }
}

