#pragma once
// ============================================================================
// OvLoader -- Runtime discovery and pre-loading of OpenVINO DLLs
//
// OpenVINO is normally import-linked (openvino.lib), but the DLLs
// must be discoverable at process load time.  OvLoader ensures the correct
// DLLs are found by:
//   1. Pre-loading Intel TBB (dependency of openvino.dll)
//   2. Pre-loading openvino.dll from the ANSCENTER shared directory
//   3. Optionally querying the OpenVINO version via the C API
//
// Plugins (CPU, GPU, NPU) and frontends (IR, ONNX, etc.) are discovered
// automatically by OpenVINO's internal plugin loader from the same directory
// once the shared directory has been injected into the DLL search path.
// ============================================================================

#include "ANSLibsLoader.h"   // ANSLIBS_API
#include "DynLibUtils.h"     // LibHandle

#include <string>
#include <vector>
#include <mutex>

// ============================================================================
struct ANSLIBS_API OvInfo
{
    std::string dllPath;        // Full path to loaded openvino.dll
    std::string version;        // e.g. "2024.6.0" (build number from C API)
    bool        loaded = false;
};

// ============================================================================
class ANSLIBS_API OvLoader
{
public:
    /// Discover and pre-load OpenVINO + TBB DLLs.
    /// Safe to call multiple times -- subsequent calls are no-ops.
    /// @param shared_dir  Directory to search first (default: ANSCENTER shared).
    /// @param verbose     Print discovery results to stdout.
    /// @returns Reference to the discovery result.
    [[nodiscard]] static const OvInfo& Initialize(
        const std::string& shared_dir = ANSCENTER::DynLib::DEFAULT_SHARED_DIR,
        bool verbose = true);

    /// Release pre-loaded library handles.
    static void Shutdown();

    /// Query current state.
    [[nodiscard]] static const OvInfo& Current() noexcept { return s_info; }
    [[nodiscard]] static bool IsInitialized()    noexcept { return s_initialized; }

private:
    /// Build candidate DLL names for each component.
    static std::vector<std::string> TbbCandidates(const std::string& shared_dir);
    static std::vector<std::string> TbbMallocCandidates(const std::string& shared_dir);
    static std::vector<std::string> OvCoreCandidates(const std::string& shared_dir);
    static std::vector<std::string> OvCApiCandidates(const std::string& shared_dir);

    /// Try to extract version string via the ov_get_openvino_version C API.
    static std::string TryGetVersion(LibHandle hOvC);

    static std::mutex s_mutex;
    static bool       s_initialized;
    static OvInfo     s_info;
    static LibHandle  s_hTbb;
    static LibHandle  s_hTbbMalloc;
    static LibHandle  s_hOvCore;
    static LibHandle  s_hOvC;
};
