// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "ANSLLM.h"
#include <memory>
#include <unordered_map>
#include <condition_variable>
#include <mutex>
#include <cstdint>

// Handle registry with refcount — prevents use-after-free when
// ReleaseANSLLMHandle is called while an operation is still running.
static std::unordered_map<ANSCENTER::ANSLLM*, int>& LLMHandleRegistry() {
	static std::unordered_map<ANSCENTER::ANSLLM*, int> s;
	return s;
}
static std::mutex& LLMHandleRegistryMutex() {
	static std::mutex m;
	return m;
}
static std::condition_variable& LLMHandleRegistryCV() {
	static std::condition_variable cv;
	return cv;
}

static void RegisterLLMHandle(ANSCENTER::ANSLLM* h) {
	std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
	LLMHandleRegistry()[h] = 1;
}

static ANSCENTER::ANSLLM* AcquireLLMHandle(ANSCENTER::ANSLLM* h) {
	std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
	auto it = LLMHandleRegistry().find(h);
	if (it == LLMHandleRegistry().end()) return nullptr;
	it->second++;
	return h;
}

static bool ReleaseLLMHandleRef(ANSCENTER::ANSLLM* h) {
	std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
	auto it = LLMHandleRegistry().find(h);
	if (it == LLMHandleRegistry().end()) return false;
	it->second--;
	if (it->second <= 0) {
		LLMHandleRegistry().erase(it);
		LLMHandleRegistryCV().notify_all();
		return true;
	}
	return false;
}

static bool UnregisterLLMHandle(ANSCENTER::ANSLLM* h) {
	std::unique_lock<std::mutex> lk(LLMHandleRegistryMutex());
	auto it = LLMHandleRegistry().find(h);
	if (it == LLMHandleRegistry().end()) return false;
	it->second--;
	bool ok = LLMHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
		auto it2 = LLMHandleRegistry().find(h);
		return it2 == LLMHandleRegistry().end() || it2->second <= 0;
	});
	if (!ok) {
		OutputDebugStringA("WARNING: UnregisterLLMHandle timed out waiting for in-flight operations\n");
	}
	LLMHandleRegistry().erase(h);
	return true;
}

// RAII guard — ensures ReleaseLLMHandleRef is always called
class LLMHandleGuard {
	ANSCENTER::ANSLLM* engine;
public:
	explicit LLMHandleGuard(ANSCENTER::ANSLLM* e) : engine(e) {}
	~LLMHandleGuard() { if (engine) ReleaseLLMHandleRef(engine); }
	ANSCENTER::ANSLLM* get() const { return engine; }
	explicit operator bool() const { return engine != nullptr; }
	LLMHandleGuard(const LLMHandleGuard&) = delete;
	LLMHandleGuard& operator=(const LLMHandleGuard&) = delete;
};

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     ) noexcept
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

// Helper: safely copy a std::string into a LabVIEW LStrHandle.
// Returns 1 on success, 0 on failure (empty string or allocation error).
static int CopyToLStrHandle(LStrHandle handle, const std::string& str) noexcept {
    if (str.empty() || handle == nullptr) return 0;
    const auto size = static_cast<int32>(str.length());
    MgErr error = DSSetHandleSize(handle, sizeof(int32) + size * sizeof(uChar));
    if (error != noErr) return 0;
    (*handle)->cnt = size;
    memcpy((*handle)->str, str.c_str(), static_cast<size_t>(size));
    return 1;
}

extern "C" ANSLLM_API int  CreateANSLLMHandle(ANSCENTER::ANSLLM** Handle, const char* licenseKey, int localLLM) {
    if (Handle == nullptr || licenseKey == nullptr) return 0;
    try {
        // Release existing handle if called twice (prevents leak from LabVIEW)
        if (*Handle) {
            if (UnregisterLLMHandle(*Handle)) {
                delete *Handle;
            }
            *Handle = nullptr;
        }

        // std::unique_ptr ensures automatic cleanup on any failure path
        auto ptr = std::make_unique<ANSCENTER::ANSLLM>();
        if (!ptr->Initialize(licenseKey, localLLM != 0)) {
            // unique_ptr automatically deletes — no leak
            *Handle = nullptr;
            return 0;
        }
        // Transfer ownership to caller on success
        *Handle = ptr.release();
        RegisterLLMHandle(*Handle);
        return 1;
    }
    catch (const std::exception&) {
        *Handle = nullptr;
        return 0;
    }
    catch (...) {
        *Handle = nullptr;
        return 0;
    }
}
static int ReleaseANSLLMHandle_Impl(ANSCENTER::ANSLLM** Handle) {
    try {
        if (!Handle || !*Handle) return 1;
        if (!UnregisterLLMHandle(*Handle)) {
            *Handle = nullptr;
            return 1;
        }
        delete *Handle;
        *Handle = nullptr;
        return 1;
    }
    catch (...) {
        if (Handle) *Handle = nullptr;
        return 0;
    }
}

extern "C" ANSLLM_API int  ReleaseANSLLMHandle(ANSCENTER::ANSLLM** Handle) {
    __try {
        return ReleaseANSLLMHandle_Impl(Handle);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        if (Handle) *Handle = nullptr;
        return 0;
    }
}

extern "C" ANSLLM_API int  SetANSLLMProvider(ANSCENTER::ANSLLM** Handle, const char* provider) {
    if (Handle == nullptr || *Handle == nullptr || provider == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetLLMProvider(provider) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  GetANSLLMProvider(ANSCENTER::ANSLLM** Handle, LStrHandle provider) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(provider, guard.get()->GetLLMProvider());
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSLLM_API int  SetApiKey(ANSCENTER::ANSLLM** Handle, const char* apiKey) {
    if (Handle == nullptr || *Handle == nullptr || apiKey == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetApiKey(apiKey) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}


extern "C" ANSLLM_API int  ANSLLMGetModelList(ANSCENTER::ANSLLM** Handle, LStrHandle modelList) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> models = guard.get()->GetModelList();
        std::string st;
        for (size_t i = 0; i < models.size(); ++i) {
            if (i > 0) st += ";";
            st += models[i];
        }
        return CopyToLStrHandle(modelList, st);
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetTranscriptMode(ANSCENTER::ANSLLM** Handle, int transcriptMode) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetTranscriptMode(transcriptMode == 1) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetModel(ANSCENTER::ANSLLM** Handle, const char* modelName) {
    if (Handle == nullptr || *Handle == nullptr || modelName == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetModel(modelName) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSLLM_API int  ANSLLMInputAddText(ANSCENTER::ANSLLM** Handle, const char* inputText) {
    if (Handle == nullptr || *Handle == nullptr || inputText == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->InputAddText(inputText) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddImageUrl(ANSCENTER::ANSLLM** Handle, const char* imageURL, const char* summary) {
    if (Handle == nullptr || *Handle == nullptr || imageURL == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddImageUrl(imageURL, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddImageFromPath(ANSCENTER::ANSLLM** Handle, const char* filePath, const char* summary) {
    if (Handle == nullptr || *Handle == nullptr || filePath == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddImageFromPath(filePath, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddImageFromBase64(ANSCENTER::ANSLLM** Handle, const char* base64Image, const char* summary) {
    if (Handle == nullptr || *Handle == nullptr || base64Image == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddImageFromBase64(base64Image, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddFileURL(ANSCENTER::ANSLLM** Handle, const char* fileURL, const char* summary) {
    if (Handle == nullptr || *Handle == nullptr || fileURL == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddFileURL(fileURL, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddFileData(ANSCENTER::ANSLLM** Handle, const char* filePath, const char* summary) {
    if (Handle == nullptr || *Handle == nullptr || filePath == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddFileData(filePath, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMCreateConversation(ANSCENTER::ANSLLM** Handle, const char* systemMessage, const char* developerMessage, const char* conversationName) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    if (systemMessage == nullptr || developerMessage == nullptr || conversationName == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->CreateConversation(systemMessage, developerMessage, conversationName) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetConversation(ANSCENTER::ANSLLM** Handle, const char* conversationName) {
    if (Handle == nullptr || *Handle == nullptr || conversationName == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetConversation(conversationName) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMAsk(ANSCENTER::ANSLLM** Handle, const char* prompt, LStrHandle response) {
    if (Handle == nullptr || *Handle == nullptr || prompt == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(response, guard.get()->Ask(prompt));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSLLM_API int  ANSLLMClearInput(ANSCENTER::ANSLLM** Handle) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->ClearInputs() ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetConversationList(ANSCENTER::ANSLLM** Handle, LStrHandle conversationList) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> convs = guard.get()->GetConversationList();
        std::string st;
        for (size_t i = 0; i < convs.size(); ++i) {
            if (i > 0) st += ";";
            st += convs[i];
        }
        return CopyToLStrHandle(conversationList, st);
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMDeleteConversation(ANSCENTER::ANSLLM** Handle, const char* conversationName) {
    if (Handle == nullptr || *Handle == nullptr || conversationName == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->DeleteConversation(conversationName) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetUTF8(ANSCENTER::ANSLLM** Handle, int utf8Mode) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetUTF8(utf8Mode == 1) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetUTF8(ANSCENTER::ANSLLM** Handle) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->GetUTF8() ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMPollAi(ANSCENTER::ANSLLM** Handle, int abort) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->PollAi(abort != 0);
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSLLM_API int  ANSLLMSetLocalLLM(ANSCENTER::ANSLLM** Handle, int localLLM) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetLocalLLM(localLLM != 0) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetOllamaBaseUrl(ANSCENTER::ANSLLM** Handle, const char* baseUrl) {
    if (Handle == nullptr || *Handle == nullptr || baseUrl == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetOllamaBaseUrl(baseUrl) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetBaseURL(ANSCENTER::ANSLLM** Handle, const char* baseURL) {
    if (Handle == nullptr || *Handle == nullptr || baseURL == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetBaseURL(baseURL) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetHeartbeatMs(ANSCENTER::ANSLLM** Handle, int heartbeatMs) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetHeartbeatMs(heartbeatMs) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetHeartbeatMs(ANSCENTER::ANSLLM** Handle) {
    if (Handle == nullptr || *Handle == nullptr) return -1;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return -1;
    try {
        return guard.get()->GetHeartbeatMs();
    }
    catch (const std::exception&) {
        return -1;
    }
    catch (...) {
        return -1;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetHostedConversation(ANSCENTER::ANSLLM** Handle, int hostedConversationMode) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetHostedConversation(hostedConversationMode == 1) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetHostedConversation(ANSCENTER::ANSLLM** Handle) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->GetHostedConversation() ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetStreamingMode(ANSCENTER::ANSLLM** Handle) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->GetStreamingMode() ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetStreamingMode(ANSCENTER::ANSLLM** Handle, int streamingMode) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetStreamingMode(streamingMode == 1) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetIdleTimeoutMs(ANSCENTER::ANSLLM** Handle) {
    if (Handle == nullptr || *Handle == nullptr) return -1;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return -1;
    try {
        return guard.get()->GetIdleTimeoutMs();
    }
    catch (const std::exception&) {
        return -1;
    }
    catch (...) {
        return -1;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetIdleTimeoutMs(ANSCENTER::ANSLLM** Handle, int idleTimeoutMs) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetIdleTimeoutMs(idleTimeoutMs) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSLLM_API int  ANSLLMSetSleepMs(ANSCENTER::ANSLLM** Handle, int sleepMs) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->SetSleepMs(sleepMs) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetLastErrorMessage(ANSCENTER::ANSLLM** Handle, LStrHandle LastErrorMessage) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(LastErrorMessage, guard.get()->GetLastErrorMessage());
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetOutputText(ANSCENTER::ANSLLM** Handle, LStrHandle outputText) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(outputText, guard.get()->GetOutputText());
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetOutputTextSb(ANSCENTER::ANSLLM** Handle, LStrHandle outputTextSb) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(*Handle));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(outputTextSb, guard.get()->GetOutputTextSb());
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

// ============================================================================
// V2 entry points — accept uint64_t handleVal by value instead of ANSLLM**
// to eliminate the LabVIEW buffer reuse bug when concurrent calls share the
// same Handle** buffer address.
// ============================================================================

extern "C" ANSLLM_API int  SetANSLLMProvider_V2(uint64_t handleVal, const char* provider) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetLLMProvider(provider) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  GetANSLLMProvider_V2(uint64_t handleVal, LStrHandle provider) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(provider, guard.get()->GetLLMProvider());
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  SetApiKey_V2(uint64_t handleVal, const char* apiKey) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetApiKey(apiKey) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetModelList_V2(uint64_t handleVal, LStrHandle modelList) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        std::vector<std::string> models = guard.get()->GetModelList();
        std::string st;
        for (size_t i = 0; i < models.size(); ++i) {
            if (i > 0) st += ";";
            st += models[i];
        }
        return CopyToLStrHandle(modelList, st);
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetTranscriptMode_V2(uint64_t handleVal, int transcriptMode) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetTranscriptMode(transcriptMode == 1) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetModel_V2(uint64_t handleVal, const char* modelName) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetModel(modelName) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddText_V2(uint64_t handleVal, const char* inputText) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->InputAddText(inputText) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddImageUrl_V2(uint64_t handleVal, const char* imageURL, const char* summary) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddImageUrl(imageURL, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddImageFromPath_V2(uint64_t handleVal, const char* filePath, const char* summary) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddImageFromPath(filePath, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddImageFromBase64_V2(uint64_t handleVal, const char* base64Image, const char* summary) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddImageFromBase64(base64Image, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddFileURL_V2(uint64_t handleVal, const char* fileURL, const char* summary) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddFileURL(fileURL, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMInputAddFileData_V2(uint64_t handleVal, const char* filePath, const char* summary) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        const char* safeSummary = (summary != nullptr) ? summary : "";
        return guard.get()->InputAddFileData(filePath, safeSummary) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMClearInput_V2(uint64_t handleVal) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->ClearInputs() ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMCreateConversation_V2(uint64_t handleVal, const char* systemMessage, const char* developerMessage, const char* conversationName) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    if (systemMessage == nullptr || developerMessage == nullptr || conversationName == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->CreateConversation(systemMessage, developerMessage, conversationName) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetConversation_V2(uint64_t handleVal, const char* conversationName) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    if (conversationName == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetConversation(conversationName) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMDeleteConversation_V2(uint64_t handleVal, const char* conversationName) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    if (conversationName == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->DeleteConversation(conversationName) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetConversationList_V2(uint64_t handleVal, LStrHandle conversationList) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        std::vector<std::string> convs = guard.get()->GetConversationList();
        std::string st;
        for (size_t i = 0; i < convs.size(); ++i) {
            if (i > 0) st += ";";
            st += convs[i];
        }
        return CopyToLStrHandle(conversationList, st);
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMAsk_V2(uint64_t handleVal, const char* prompt, LStrHandle response) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    if (prompt == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(response, guard.get()->Ask(prompt));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMPollAi_V2(uint64_t handleVal, int abort) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->PollAi(abort != 0);
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetUTF8_V2(uint64_t handleVal, int utf8Mode) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetUTF8(utf8Mode == 1) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetUTF8_V2(uint64_t handleVal) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->GetUTF8() ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetLocalLLM_V2(uint64_t handleVal, int localLLM) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetLocalLLM(localLLM != 0) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetOllamaBaseUrl_V2(uint64_t handleVal, const char* baseUrl) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    if (baseUrl == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetOllamaBaseUrl(baseUrl) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetBaseURL_V2(uint64_t handleVal, const char* baseURL) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    if (baseURL == nullptr) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetBaseURL(baseURL) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetHeartbeatMs_V2(uint64_t handleVal, int heartbeatMs) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetHeartbeatMs(heartbeatMs) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetHeartbeatMs_V2(uint64_t handleVal) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return -1;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return -1;
    try {
        return guard.get()->GetHeartbeatMs();
    }
    catch (const std::exception&) {
        return -1;
    }
    catch (...) {
        return -1;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetHostedConversation_V2(uint64_t handleVal, int hostedConversationMode) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetHostedConversation(hostedConversationMode == 1) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetHostedConversation_V2(uint64_t handleVal) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->GetHostedConversation() ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetStreamingMode_V2(uint64_t handleVal) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->GetStreamingMode() ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetStreamingMode_V2(uint64_t handleVal, int streamingMode) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetStreamingMode(streamingMode == 1) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetIdleTimeoutMs_V2(uint64_t handleVal) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return -1;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return -1;
    try {
        return guard.get()->GetIdleTimeoutMs();
    }
    catch (const std::exception&) {
        return -1;
    }
    catch (...) {
        return -1;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetIdleTimeoutMs_V2(uint64_t handleVal, int idleTimeoutMs) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetIdleTimeoutMs(idleTimeoutMs) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMSetSleepMs_V2(uint64_t handleVal, int sleepMs) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return guard.get()->SetSleepMs(sleepMs) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetLastErrorMessage_V2(uint64_t handleVal, LStrHandle LastErrorMessage) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(LastErrorMessage, guard.get()->GetLastErrorMessage());
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetOutputText_V2(uint64_t handleVal, LStrHandle outputText) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(outputText, guard.get()->GetOutputText());
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSLLM_API int  ANSLLMGetOutputTextSb_V2(uint64_t handleVal, LStrHandle outputTextSb) {
    auto* _v2h = reinterpret_cast<ANSCENTER::ANSLLM*>(handleVal); if (!_v2h) return 0;
    LLMHandleGuard guard(AcquireLLMHandle(_v2h));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(outputTextSb, guard.get()->GetOutputTextSb());
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
