// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "ANSMOT.h"
#include "ANSByteTrackNCNN.h"
#include "ANSByteTrack.h"
#include "ANSByteTrackEigen.h"
#include "ANSOCSortTrack.h"
#include "ANSUCMC.h"
#include <unordered_map>
#include <condition_variable>
#include <mutex>
#include <cstdint>

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

static void RegisterMOTHandle(ANSCENTER::ANSMOT* h) {
	std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
	MOTHandleRegistry()[h] = 1;
}

static ANSCENTER::ANSMOT* AcquireMOTHandle(ANSCENTER::ANSMOT* h) {
	std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
	auto it = MOTHandleRegistry().find(h);
	if (it == MOTHandleRegistry().end()) return nullptr;
	it->second++;
	return h;
}

static bool ReleaseMOTHandleRef(ANSCENTER::ANSMOT* h) {
	std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
	auto it = MOTHandleRegistry().find(h);
	if (it == MOTHandleRegistry().end()) return false;
	it->second--;
	if (it->second <= 0) {
		MOTHandleRegistry().erase(it);
		MOTHandleRegistryCV().notify_all();
		return true;
	}
	return false;
}

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

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

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
/*
   enum MOTEType {
		BYTETRACKNCNN = 0,
		BYTETRACK = 1,
		BYTETRACKEIGEN=2,
		OCSORT=3
	};
*/
extern "C" __declspec(dllexport) int      __cdecl CreateANSMOTHandle(ANSCENTER::ANSMOT **Handle, int motType) {
	if (Handle == nullptr) return 0;
	try {
		// Release existing handle if called twice (prevents leak from LabVIEW)
		if (*Handle) {
			if (UnregisterMOTHandle(*Handle)) {
				(*Handle)->Destroy();
				delete *Handle;
			}
			*Handle = nullptr;
		}

		switch (motType) {
		case 0: //BYTETRACKNCNN =0
			(*Handle) = new ANSCENTER::ANSByteTrack();// ANSByteTrackNCNN();
			break;
		case 1: //BYTETRACK = 1
			(*Handle) = new ANSCENTER::ANSByteTrack();
			break;
		case 2://BYTETRACKEIGEN = 2
			(*Handle) = new ANSCENTER::ANSByteTrack();// ANSByteTrackEigen();
			break;
		case 3://UCMC = 3
			(*Handle) = new ANSCENTER::ANSUCMCTrack();
			break;
		case 4://OCSORT = 4
			(*Handle) = new ANSCENTER::ANSOCSortTrack();
			break;
		default:
			(*Handle) = new ANSCENTER::ANSByteTrack();// ANSByteTrackNCNN();
			break;
		}
		if (*Handle == nullptr) {
			return 0;
		}
		else {
			RegisterMOTHandle(*Handle);
			return 1;
		}
	}
	catch (std::exception& e) {
		return 0;
	}
	catch (...) {
		return 0;
	}
}
static int ReleaseANSMOTHandle_Impl(ANSCENTER::ANSMOT** Handle) {
	try {
		if (!Handle || !*Handle) return 1;
		if (!UnregisterMOTHandle(*Handle)) {
			*Handle = nullptr;
			return 1;
		}
		(*Handle)->Destroy();
		delete *Handle;
		*Handle = nullptr;
		return 1;
	}
	catch (...) {
		if (Handle) *Handle = nullptr;
		return 0;
	}
}

extern "C" __declspec(dllexport) int      __cdecl ReleaseANSMOTHandle(ANSCENTER::ANSMOT **Handle) {
	__try {
		return ReleaseANSMOTHandle_Impl(Handle);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		if (Handle) *Handle = nullptr;
		return 0;
	}
}

extern "C" __declspec(dllexport) int     __cdecl UpdateANSMOTParameters(ANSCENTER::ANSMOT * *Handle, const char* trackerParameter) {
	if (Handle == nullptr || *Handle == nullptr) return -1;
	MOTHandleGuard guard(AcquireMOTHandle(*Handle));
	if (!guard) return -1;
	try {
		bool result = guard.get()->UpdateParameters(trackerParameter);
		if (result) return 1;
		else return 0;
	}
	catch (std::exception& e) {
		return 0;
	}
	catch (...) {
		return 0;
	}
}

extern "C" __declspec(dllexport) int __cdecl UpdateANSMOT(ANSCENTER::ANSMOT * *Handle, int modelId, const char* detectionData, std::string & result) {
	if (Handle == nullptr || *Handle == nullptr) return -1;
	MOTHandleGuard guard(AcquireMOTHandle(*Handle));
	if (!guard) return -1;
	try {
		result = guard.get()->Update(modelId, detectionData);
		if (result.empty())return 0;
		else return 1;
	}
	catch (std::exception& e) {
		return 0;
	}
	catch (...) {
		return 0;
	}
}
extern "C" __declspec(dllexport) int            __cdecl UpdateANSMOT_LV(ANSCENTER::ANSMOT * *Handle, int modelId, const char* detectionData, LStrHandle trackerResult) {
	if (Handle == nullptr || *Handle == nullptr) return -1;
	MOTHandleGuard guard(AcquireMOTHandle(*Handle));
	if (!guard) return -1;
	try {
		std::string st = guard.get()->Update(modelId, detectionData);
		int size = static_cast<int>(st.length());
		MgErr error;
		error = DSSetHandleSize(trackerResult, sizeof(int32) + size * sizeof(uChar));
		if (error == noErr)
		{
			(*trackerResult)->cnt = size;
			memcpy((*trackerResult)->str, st.c_str(), size);
			return 1;
		}
		else return 0;
	}
	catch (std::exception& e) {
		return 0;
	}
	catch (...) {
		return 0;
	}
}

extern "C" __declspec(dllexport) int            __cdecl UpdateANSMOTTracker(ANSCENTER::ANSMOT** Handle, int modelId, const std::vector<ANSCENTER::TrackerObject>& detectionObjects, std::vector<ANSCENTER::TrackerObject>& trackedObjects)
{
	if (Handle == nullptr || *Handle == nullptr) return -1;
	MOTHandleGuard guard(AcquireMOTHandle(*Handle));
	if (!guard) return -1;
	try {
		trackedObjects = guard.get()->UpdateTracker(modelId, detectionObjects);
		if (trackedObjects.empty()) return 0;
		else return 1;
	}
	catch (std::exception& e) {
		return 0;
	}
	catch (...) {
		return 0;
	}
}

// ============================================================================
// V2 LabVIEW API — Accept handle as uint64_t by value.
// Eliminates Handle** pointer-to-pointer instability when LabVIEW calls
// concurrently from multiple tasks.
// LabVIEW CLFN: set Handle parameter to Numeric / Unsigned Pointer-sized Integer / Pass: Value
// ============================================================================

extern "C" __declspec(dllexport) int __cdecl UpdateANSMOT_LV_V2(uint64_t handleVal, int modelId, const char* detectionData, LStrHandle trackerResult) {
	ANSCENTER::ANSMOT* directHandle = reinterpret_cast<ANSCENTER::ANSMOT*>(handleVal);
	if (directHandle == nullptr) return -1;
	MOTHandleGuard guard(AcquireMOTHandle(directHandle));
	if (!guard) return -1;
	try {
		std::string st = guard.get()->Update(modelId, detectionData);
		int size = static_cast<int>(st.length());
		MgErr error = DSSetHandleSize(trackerResult, sizeof(int32) + size * sizeof(uChar));
		if (error == noErr) {
			(*trackerResult)->cnt = size;
			memcpy((*trackerResult)->str, st.c_str(), size);
			return 1;
		}
		else return 0;
	}
	catch (...) { return 0; }
}