#ifndef ANSTRE_H
#define ANSTRE_H
#define ANSTRE_API __declspec(dllexport)
#pragma once
#include <cstdint>
#include <iostream>
#include <vector>
#include "LabVIEWHeader/extcode.h"
#include "ANSLicense.h"
#include <map>

namespace ANSCENTER {
	class ANSTRE_API ANSTRE {
	public:
		[[nodiscard]] virtual bool Init(std::string licenseKey, std::string projectDirectory, std::string engineDirectory, std::string modelTemplateDirectory, std::string modelZipPassword, bool isLatestEngine)=0;
		[[nodiscard]] virtual std::vector<std::string> GetProjects()=0;// Return a list of projects in the project directory
		[[nodiscard]] virtual std::vector<std::string> GetProjectExperiments(std::string projectName)=0;// Return a list of experiments for a specific project
		[[nodiscard]] virtual bool CreateProject(std::string projectName) = 0;
		[[nodiscard]] virtual bool DeleteProject(std::string projectName)=0;
		[[nodiscard]] virtual bool SetWorkingDirectory(std::string workingDirectory)=0;
		[[nodiscard]] virtual bool UploadTrainingData(std::string projectName)=0;	// Upload the training data to the project
		[[nodiscard]] virtual bool CreateTrainingEngine(std::string projectName, int experimentNumber, int extractorType, long numberStep, int batchSize, double learningRate)=0;// extractorType =0: FAST, 1: ACCURATE; 2: VERY ACCURATE
		[[nodiscard]] virtual std::string GetProjectExperimentStatus(std::string projectName, int experimentNumber)=0;// Return the status of a specific experiment
		[[nodiscard]] virtual std::string GenerateTrainingCommand(std::string projectName, int experimentNumber, int extractorType)=0; //Generate the training command
		[[nodiscard]] virtual std::string GenerateCustomTrainingCommand(std::string projectName, int experimentNumber, int extractorType, std::string pretrainModel) = 0; //Generate the training command
		[[nodiscard]] virtual std::string GenerateEvaluateModelCommand(std::string projectName, int experimentNumber, bool& zipModelExist)=0;		   //Evaluate the accuracy of the model
		[[nodiscard]] virtual std::string EvaluateModel(std::string projectName, int experimentNumber)=0;		   //Evaluate the accuracy of the model
		[[nodiscard]] virtual bool DownloadModel(std::string projectName, int experimentNumber, std::string destZipDirectory, int modelModel = 0)=0;
		[[nodiscard]] virtual std::string ParseTrainingResults(std::string trainingResults)=0;
		[[nodiscard]] virtual bool CheckEngineStatus() = 0;
		[[nodiscard]] virtual bool CheckEngine() = 0;
		[[nodiscard]] virtual std::string GenerateTestCommand(std::string projectName, int experimentNumber, bool& zipModelExist, const std::string& testDataFolder) = 0; //Generate the test command


		[[nodiscard]] std::string GetProjectDirectory() { return _projectDirectory; }
		[[nodiscard]] bool ZipExperiment(std::string projectName, int experimentNumber);
		[[nodiscard]] bool IsProcessRunning(const char* processName);
		[[nodiscard]] double ParseObjectDetectionMAP(std::string stEvaluationResult);
		[[nodiscard]] std::string GetLatestValidFolderAndDeleteOthers(const std::string& projectName, const std::string& rootPath);
	protected:
		std::string _licenseKey;
		bool _isLicenseValid{ false };
		bool _changeProjectDirectory{ false };
		bool _isLatestEngine{ false }; // If the engine is the latest version. For example, Object Detection uses Yolov10
		std::string _zipPassword;
		std::string _modelZipPassword;
		std::string _projectDirectory; // Project directory C:\ProgramData\Sh7O7nUe7vJ
		std::string _engineDirectory; // C:\ProgramData\mt5P9nTe5vG\Engine\CUDA11 (will be replaced by ANS Runtime Engine)	
		std::string _modelTemplateDirectory; // C:\ProgramData\mt5P9nTe5vG\Engine\CUDA11 (could be in the same data folder of the installation folder)	
		std::string _workingDirectory; // C:\Programs\AITraining\Mask (the current project working directory)
		std::string _projectName; // 
		int _currentExperimentNumber{ 0 }; //
		SPDLogger& _logger = SPDLogger::GetInstance("ANSTRE", false);
		std::vector<std::string> _projects;
		std::string ExecuteCommand(const char* cmd);
		std::vector<std::string> ParseANSClass(const std::string& ansClassFileName);
		std::string ConvertVectorToClass(const std::vector<std::string>& vec);
	};
}
// trainingEngineType =0: ODHUB, =1: Object Detection, =2: Classification, =3: Segmentation; =4: Abnomally Detection
extern "C" ANSTRE_API int  CreateANSTREHandle(ANSCENTER::ANSTRE** Handle, const char* licenseKey, const char* projectDirectory, const char* engineDirectory, const char* modelTemplateDirectory, const char* modelZipPassword, int trainingEngineType, int latestEngine);
extern "C" ANSTRE_API int  ReleaseANSTREHandle(ANSCENTER::ANSTRE** Handle);
extern "C" ANSTRE_API int  ANSTRE_GetProjects(ANSCENTER::ANSTRE** Handle, LStrHandle strProjects);
extern "C" ANSTRE_API int  ANSTRE_GetProjectExperiments(ANSCENTER::ANSTRE** Handle, const char* projectName, LStrHandle strProjectExperiments);
extern "C" ANSTRE_API int  ANSTRE_CreateProject(ANSCENTER::ANSTRE** Handle, const char* projectName);
extern "C" ANSTRE_API int  ANSTRE_DeleteProject(ANSCENTER::ANSTRE** Handle, const char* projectName);
extern "C" ANSTRE_API int  ANSTRE_SetWorkingDirectory(ANSCENTER::ANSTRE** Handle, const char* workingDirectory);
extern "C" ANSTRE_API int  ANSTRE_UploadTrainingData(ANSCENTER::ANSTRE** Handle, const char* projectName);
extern "C" ANSTRE_API int  ANSTRE_CreateTrainingEngine(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, int extractorType, long numberStep, int batchSize, double learningRate);
extern "C" ANSTRE_API int  ANSTRE_GetProjectExperimentStatus(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, LStrHandle projectStatus);
extern "C" ANSTRE_API int  ANSTRE_GenerateTrainingCommand(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, int extractorType, LStrHandle trainingCommand);
extern "C" ANSTRE_API int  ANSTRE_GenerateCustomTrainingCommand(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, int extractorType, const char* pretrainedModel,LStrHandle trainingCommand);

extern "C" ANSTRE_API int  ANSTRE_EvaluateModel(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, LStrHandle mAPResult);
extern "C" ANSTRE_API int  ANSTRE_EvaluateModelOnTestData(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, const char* dataFolder, LStrHandle evaluationCommand);
extern "C" ANSTRE_API int  ANSTRE_DownloadModel(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, const char* downloadDirDestination, int modelMode);
extern "C" ANSTRE_API int  ANSTRE_GetProjectDirectory(ANSCENTER::ANSTRE** Handle, LStrHandle strProjectDir);
extern "C" ANSTRE_API int  ANSTRE_ZipExperiment(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber);
extern "C" ANSTRE_API double  ANSTRE_ParseMAP(ANSCENTER::ANSTRE** Handle, const char* evaluationResult);
extern "C" ANSTRE_API int  ANSTRE_ParseTrainingResults(ANSCENTER::ANSTRE** Handle, const char* trainingResult, LStrHandle strResult);
extern "C" ANSTRE_API int  ANSTRE_CheckEngineStatus(ANSCENTER::ANSTRE** Handle);
extern "C" ANSTRE_API int  ANSTRE_CheckEngine(ANSCENTER::ANSTRE** Handle);


//C++ API
extern "C" ANSTRE_API int  ANSTRE_GetProjects_CPP(ANSCENTER::ANSTRE** Handle, std::string& strProjects);
extern "C" ANSTRE_API int  ANSTRE_GetProjectExperiments_CPP(ANSCENTER::ANSTRE** Handle, const char* projectName, std::string& strProjectExperiments);
extern "C" ANSTRE_API int  ANSTRE_GetProjectExperimentStatus_CPP(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, std::string& projectStatus);
extern "C" ANSTRE_API int  ANSTRE_GenerateTrainingCommand_CPP(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, int extractorType, std::string& trainingCommand);
extern "C" ANSTRE_API int  ANSTRE_GenerateCustomTrainingCommand_CPP(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, int extractorType, const char* pretrainedModel, std::string& trainingCommand);

extern "C" ANSTRE_API int  ANSTRE_EvaluateModel_CPP(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, std::string& mAPResult);
extern "C" ANSTRE_API int  ANSTRE_EvaluateModelOnTestData_CPP(ANSCENTER::ANSTRE** Handle, const char* projectName, int experimentNumber, const char* dataFolder,std::string& evaluationCommand);
extern "C" ANSTRE_API int  ANSTRE_GetProjectDirectory_CPP(ANSCENTER::ANSTRE** Handle, std::string& strProjectDir);
extern "C" ANSTRE_API int  ANSTRE_ParseTrainingResults_CPP(ANSCENTER::ANSTRE** Handle, const char* trainingResult, std::string& strResult);

// V2 API — accepts uint64_t handleVal by value (LabVIEW handle-by-value fix)
extern "C" ANSTRE_API int  ANSTRE_GetProjects_V2(uint64_t handleVal, LStrHandle strProjects);
extern "C" ANSTRE_API int  ANSTRE_GetProjectExperiments_V2(uint64_t handleVal, const char* projectName, LStrHandle strProjectExperiments);
extern "C" ANSTRE_API int  ANSTRE_CreateProject_V2(uint64_t handleVal, const char* projectName);
extern "C" ANSTRE_API int  ANSTRE_DeleteProject_V2(uint64_t handleVal, const char* projectName);
extern "C" ANSTRE_API int  ANSTRE_SetWorkingDirectory_V2(uint64_t handleVal, const char* workingDirectory);
extern "C" ANSTRE_API int  ANSTRE_UploadTrainingData_V2(uint64_t handleVal, const char* projectName);
extern "C" ANSTRE_API int  ANSTRE_CreateTrainingEngine_V2(uint64_t handleVal, const char* projectName, int experimentNumber, int extractorType, long numberStep, int batchSize, double learningRate);
extern "C" ANSTRE_API int  ANSTRE_GetProjectExperimentStatus_V2(uint64_t handleVal, const char* projectName, int experimentNumber, LStrHandle projectStatus);
extern "C" ANSTRE_API int  ANSTRE_GenerateTrainingCommand_V2(uint64_t handleVal, const char* projectName, int experimentNumber, int extractorType, LStrHandle trainingCommand);
extern "C" ANSTRE_API int  ANSTRE_GenerateCustomTrainingCommand_V2(uint64_t handleVal, const char* projectName, int experimentNumber, int extractorType, const char* pretrainedModel, LStrHandle trainingCommand);
extern "C" ANSTRE_API int  ANSTRE_EvaluateModel_V2(uint64_t handleVal, const char* projectName, int experimentNumber, LStrHandle mAPResult);
extern "C" ANSTRE_API int  ANSTRE_EvaluateModelOnTestData_V2(uint64_t handleVal, const char* projectName, int experimentNumber, const char* dataFolder, LStrHandle evaluationCommand);
extern "C" ANSTRE_API int  ANSTRE_DownloadModel_V2(uint64_t handleVal, const char* projectName, int experimentNumber, const char* downloadDirDestination, int modelMode);
extern "C" ANSTRE_API int  ANSTRE_GetProjectDirectory_V2(uint64_t handleVal, LStrHandle strProjectDir);
extern "C" ANSTRE_API int  ANSTRE_ZipExperiment_V2(uint64_t handleVal, const char* projectName, int experimentNumber);
extern "C" ANSTRE_API double  ANSTRE_ParseMAP_V2(uint64_t handleVal, const char* evaluationResult);
extern "C" ANSTRE_API int  ANSTRE_ParseTrainingResults_V2(uint64_t handleVal, const char* trainingResult, LStrHandle strResult);
extern "C" ANSTRE_API int  ANSTRE_CheckEngineStatus_V2(uint64_t handleVal);
extern "C" ANSTRE_API int  ANSTRE_CheckEngine_V2(uint64_t handleVal);

#endif
