#include <softbus_core/plugin/PluginLoader.h>

#include <softbus_core/logging/Logger.h>

#ifdef SOFTBUS_PLATFORM_WINDOWS
#include <windows.h>
#else
#include <dlfcn.h>
#endif

namespace softbus::core {

PluginLoader::~PluginLoader()
{
    unload();
}

bool PluginLoader::load(const std::string& pluginPath)
{
    unload();

#ifdef SOFTBUS_PLATFORM_WINDOWS
    handle_ = LoadLibraryA(pluginPath.c_str());
    if (!handle_) {
        SB_LOG_ERROR("PluginLoader", "Failed to load plugin: ", pluginPath);
        return false;
    }
    auto createFramer = reinterpret_cast<CreateFramerFn>(GetProcAddress(static_cast<HMODULE>(handle_), "create_framer"));
    auto destroyFramer = reinterpret_cast<DestroyFramerFn>(GetProcAddress(static_cast<HMODULE>(handle_), "destroy_framer"));
    auto createParser = reinterpret_cast<CreateParserFn>(GetProcAddress(static_cast<HMODULE>(handle_), "create_parser"));
    auto destroyParser = reinterpret_cast<DestroyParserFn>(GetProcAddress(static_cast<HMODULE>(handle_), "destroy_parser"));
#else
    handle_ = dlopen(pluginPath.c_str(), RTLD_NOW | RTLD_LOCAL);
    if (!handle_) {
        SB_LOG_ERROR("PluginLoader", "Failed to load plugin: ", pluginPath, " err=", dlerror());
        return false;
    }
    auto createFramer = reinterpret_cast<CreateFramerFn>(dlsym(handle_, "create_framer"));
    auto destroyFramer = reinterpret_cast<DestroyFramerFn>(dlsym(handle_, "destroy_framer"));
    auto createParser = reinterpret_cast<CreateParserFn>(dlsym(handle_, "create_parser"));
    auto destroyParser = reinterpret_cast<DestroyParserFn>(dlsym(handle_, "destroy_parser"));
#endif

    if (!createFramer || !destroyFramer || !createParser || !destroyParser) {
        SB_LOG_ERROR("PluginLoader", "Plugin missing required exports: ", pluginPath);
        unload();
        return false;
    }

    destroyFramer_ = destroyFramer;
    destroyParser_ = destroyParser;
    framer_ = createFramer();
    parser_ = createParser();
    if (!framer_ || !parser_) {
        unload();
        return false;
    }

    SB_LOG_INFO("PluginLoader", "Loaded plugin: ", pluginPath);
    return true;
}

void PluginLoader::unload()
{
    if (framer_ && destroyFramer_) {
        destroyFramer_(framer_);
    }
    if (parser_ && destroyParser_) {
        destroyParser_(parser_);
    }
    framer_ = nullptr;
    parser_ = nullptr;
    destroyFramer_ = nullptr;
    destroyParser_ = nullptr;

    if (handle_) {
#ifdef SOFTBUS_PLATFORM_WINDOWS
        FreeLibrary(static_cast<HMODULE>(handle_));
#else
        dlclose(handle_);
#endif
        handle_ = nullptr;
    }
}

} // namespace softbus::core
