#include "mpv_loader.h"
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

/* Global function pointers */
p_mpv_error_string mpv_error_string = NULL;
p_mpv_create mpv_create = NULL;
p_mpv_initialize mpv_initialize = NULL;
p_mpv_terminate_destroy mpv_terminate_destroy = NULL;
p_mpv_set_option_string mpv_set_option_string = NULL;
p_mpv_set_wakeup_callback mpv_set_wakeup_callback = NULL;
p_mpv_command_async mpv_command_async = NULL;
p_mpv_command mpv_command = NULL;
p_mpv_set_property_async mpv_set_property_async = NULL;
p_mpv_set_property mpv_set_property = NULL;
p_mpv_get_property mpv_get_property = NULL;
p_mpv_free mpv_free = NULL;
p_mpv_set_property_string mpv_set_property_string = NULL;
p_mpv_wait_event mpv_wait_event = NULL;
p_mpv_observe_property mpv_observe_property = NULL;
p_mpv_unobserve_property mpv_unobserve_property = NULL;
p_mpv_event_name mpv_event_name = NULL;

static void *lib_handle = NULL;

int load_mpv_library(void)
{
    if (lib_handle) return 0;

    const char *lib_names[] = {
        "./lib/libmpv.so.2",
        "./libmpv.so.2",
        "libmpv.so.2",
        "libmpv.so.1",
        "libmpv.so"
    };

    for (size_t i = 0; i < sizeof(lib_names) / sizeof(lib_names[0]); i++) {
        lib_handle = dlopen(lib_names[i], RTLD_LAZY);
        if (lib_handle) {
            printf("Loaded mpv library from: %s\n", lib_names[i]);
            break;
        }
    }

    if (!lib_handle) {
        fprintf(stderr, "Failed to load libmpv: %s\n", dlerror());
        return -1;
    }

#define LOAD_SYM(name) \
    mpv_##name = (p_mpv_##name)dlsym(lib_handle, "mpv_" #name); \
    if (!mpv_##name) { \
        fprintf(stderr, "Failed to find symbol mpv_" #name ": %s\n", dlerror()); \
        unload_mpv_library(); \
        return -1; \
    }

    LOAD_SYM(error_string);
    LOAD_SYM(create);
    LOAD_SYM(initialize);
    LOAD_SYM(terminate_destroy);
    LOAD_SYM(set_option_string);
    LOAD_SYM(set_wakeup_callback);
    LOAD_SYM(command_async);
    LOAD_SYM(command);
    LOAD_SYM(set_property_async);
    LOAD_SYM(set_property);
    LOAD_SYM(get_property);
    LOAD_SYM(free);
    LOAD_SYM(set_property_string);
    LOAD_SYM(wait_event);
    LOAD_SYM(observe_property);
    LOAD_SYM(unobserve_property);
    LOAD_SYM(event_name);

    return 0;
}

void unload_mpv_library(void)
{
    if (lib_handle) {
        dlclose(lib_handle);
        lib_handle = NULL;
    }
}
