#pragma once
#ifndef EPLOADER_H
#define EPLOADER_H

// ============================================================================
// EPLoader — Dynamic ONNX Runtime loader
//
// Moved from ONNXEngine/ to ANSLibsLoader/ for centralized library management.
// Now exported via ANSLIBS_API from ANSLibsLoader.dll.
// ============================================================================

#include "ANSLibsLoader.h"   // ANSLIBS_API, EngineType

#include <string>
#include <mutex>

namespace ANSCENTER {

    struct EPInfo {
        EngineType  type = EngineType::CPU;
        std::string name;               // "CUDA", "OpenVINO", "DirectML", "CPU"
        std::string ortProviderName;    // exact ORT provider string
        std::string libraryDir;         // resolved absolute path to EP DLLs
        bool        fromSubdir = false; // true = ep/<name>/, false = flat Shared/
    };

    class ANSLIBS_API EPLoader
    {
    public:

        // ── Platform defaults ────────────────────────────────────────────────
#ifdef _WIN32
        static constexpr const char* DEFAULT_SHARED_DIR =
            "C:\\ProgramData\\ANSCENTER\\Shared";
#else
        static constexpr const char* DEFAULT_SHARED_DIR =
            "/opt/anscenter/shared";
#endif

        // ── Initialize ───────────────────────────────────────────────────────
        /// Call once at application startup (optional — Current() lazy-inits).
        ///
        /// @param shared_dir   Root deployment directory.
        ///                     Expected subdirectory layout:
        ///                       <shared_dir>/ep/cuda/onnxruntime.dll
        ///                       <shared_dir>/ep/directml/onnxruntime.dll
        ///                       <shared_dir>/ep/openvino/onnxruntime.dll
        ///                       <shared_dir>/ep/cpu/onnxruntime.dll
        ///                     Falls back to <shared_dir>/onnxruntime.dll if
        ///                     subdirectories are absent (backward compat).
        ///
        /// @param preferred    Force a specific EP.
        ///                     Pass EngineType::AUTO_DETECT to let AutoDetect()
        ///                     query ANSLicenseHelper (default).
        ///
        /// @return             Const reference to the populated EPInfo.
        ///                     Valid for the lifetime of the process.
        ///
        /// @throws std::runtime_error if onnxruntime.dll cannot be loaded or
        ///         OrtGetApiBase is not found in the DLL.
        [[nodiscard]] static const EPInfo& Initialize(
            const std::string& shared_dir = DEFAULT_SHARED_DIR,
            EngineType preferred = EngineType::AUTO_DETECT);

        // ── Current ──────────────────────────────────────────────────────────
        /// Returns the active EPInfo. Calls Initialize() with default arguments
        /// on the first invocation (lazy auto-init). Thread-safe.
        [[nodiscard]] static const EPInfo& Current();

        // ── AutoDetect ───────────────────────────────────────────────────────
        /// Delegates to ANSLicenseHelper::CheckHardwareInformation().
        /// Priority: NVIDIA > AMD > Intel (OpenVINO) > CPU.
        [[nodiscard]] static EngineType AutoDetect();

        // ── IsInitialized ────────────────────────────────────────────────────
        [[nodiscard]] static bool IsInitialized();

        // ── EngineTypeName ───────────────────────────────────────────────────
        [[nodiscard]] static const char* EngineTypeName(EngineType type);

        // ── SubdirName ───────────────────────────────────────────────────────
        /// Returns the ep/ subdirectory name for a given EngineType.
        /// e.g. EngineType::NVIDIA_GPU → "cuda"
        [[nodiscard]] static const char* SubdirName(EngineType type);
        [[nodiscard]] static void* GetOrtApiRaw();

        // ── Shutdown ─────────────────────────────────────────────────────────
        /// Releases the onnxruntime.dll handle.
        /// Call at application exit AFTER all Ort::Session objects are destroyed.
        /// Safe to call multiple times.
        static void Shutdown();

        // ── Non-copyable / non-movable ───────────────────────────────────────
        EPLoader() = delete;
        EPLoader(const EPLoader&) = delete;
        EPLoader& operator=(const EPLoader&) = delete;

    private:

        static std::string ResolveEPDir(const std::string& shared_dir,
            EngineType type);
        static void LoadOrtDll(const std::string& ep_dir);

        // ── State ────────────────────────────────────────────────────────────
        // Defined in EPLoader.cpp only when ANSLIBSLOADER_EXPORTS is set.
        static std::mutex  s_mutex;
        static bool        s_initialized;
        static EPInfo      s_info;
#ifdef _WIN32
        static std::string  s_temp_ort_path;
        static std::string  s_temp_dir;
#endif
    };
} // namespace ANSCENTER

#endif // EPLOADER_H
