#include "ANSFD.h"

namespace ANSCENTER {

	bool ANSFD::OptimizeModel(bool fp16, std::string& optimizedModelFolder) {
		if (!ANSODBase::OptimizeModel(fp16, optimizedModelFolder)) {
			return false;
		}
		if (_engineType == EngineType::NVIDIA_GPU) // NVIDIA CUDA
		{
			return _gpufaceDetector.OptimizeModel(fp16, optimizedModelFolder);
		}
		else {
			return _cpufaceDetector.OptimizeModel(fp16, optimizedModelFolder);
		}
	}

	bool ANSFD::LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) {
		try {
			if (_engineType == EngineType::NVIDIA_GPU) // NVIDIA CUDA
			{
				return _gpufaceDetector.LoadModel(modelZipFilePath, modelZipPassword);
			}
			else {
				return _cpufaceDetector.LoadModel(modelZipFilePath, modelZipPassword);
			}
		}
		catch (std::exception& e) {
			this->_logger.LogFatal("ANSFD::LoadModel", e.what(), __FILE__, __LINE__);
			return false;
		}
	}

	bool ANSFD::LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap) {
		try {
			if (_engineType == EngineType::NVIDIA_GPU) // NVIDIA CUDA
			{
				return _gpufaceDetector.LoadModelFromFolder(licenseKey, modelConfig,modelName, className,modelFolder,labelMap);
			}
			else {
				return _cpufaceDetector.LoadModelFromFolder(licenseKey, modelConfig,modelName, className,modelFolder,labelMap);
			}
		}
		catch (std::exception& e) {
			this->_logger.LogFatal("ANSFD::LoadModel", e.what(), __FILE__, __LINE__);
			return false;
		}
	}

	bool ANSFD::Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) {
		try {
            ANSODBase::CheckLicense();
            if (!_licenseValid) return false;
            _modelConfig = modelConfig;
            _modelConfig.modelType = ModelType::FACEDETECT;  
            _modelConfig.detectionType = DetectionType::FACEDETECTOR;
			_engineType = ANSLicenseHelper::CheckHardwareInformation();
			if (_engineType == EngineType::NVIDIA_GPU) // NVIDIA CUDA
			{
				_isInitialized = _gpufaceDetector.Initialize(licenseKey, _modelConfig, modelZipFilePath, modelZipPassword, labelMap);
				return _isInitialized;
			}
			else {
				_isInitialized = _cpufaceDetector.Initialize(licenseKey, _modelConfig, modelZipFilePath, modelZipPassword, labelMap);
				return _isInitialized;
			}

		}
		catch (std::exception& e) {
			this->_logger.LogFatal("ANSFD::Initialize", e.what(), __FILE__, __LINE__);
			return false;
		}
	}
	std::vector<Object> ANSFD::RunInference(const cv::Mat& input) {
		return RunInference(input, "CustomCam");
	}

	std::vector<Object> ANSFD::RunInference(const cv::Mat& input, const std::string& camera_id) {
		std::vector<Object> output;
		try {
			// 1. Basic system checks
			if (!_licenseValid) {
				this->_logger.LogError("ANSFD::RunInference", "Invalid License", __FILE__, __LINE__);
				return output;
			}
			if (!_isInitialized) {
				this->_logger.LogError("ANSFD::RunInference", "Model is not initialized", __FILE__, __LINE__);
				return output;
			}

			// 2. Input validation
			if (input.empty() || input.cols < 10 || input.rows < 10) {
				this->_logger.LogError("ANSFD::RunInference", "Invalid input image", __FILE__, __LINE__);
				return output;
			}

			// 3. Run GPU or CPU inference safely
			if (_engineType == EngineType::NVIDIA_GPU) {
				try {
					output = _gpufaceDetector.RunInference(input, camera_id);
				}
				catch (const std::exception& e) {
					this->_logger.LogError("ANSFD::RunInference", std::string("GPU inference failed: ") + e.what(), __FILE__, __LINE__);
				}
			}
			else {
				try {
					output = _cpufaceDetector.RunInference(input, camera_id);
				}
				catch (const std::exception& e) {
					this->_logger.LogError("ANSFD::RunInference", std::string("CPU inference failed: ") + e.what(), __FILE__, __LINE__);
				}
			}
		}
		catch (const std::exception& e) {
			this->_logger.LogFatal("ANSFD::RunInference", std::string("Unhandled exception: ") + e.what(), __FILE__, __LINE__);
		}
		catch (...) {
			this->_logger.LogFatal("ANSFD::RunInference", "Unknown fatal exception occurred", __FILE__, __LINE__);
		}

		if (_trackerEnabled) {
			output = ApplyTracking(output, camera_id);
			if (_stabilizationEnabled) output = StabilizeDetections(output, camera_id);
		}
		return output;
	}

	
	ANSFD::~ANSFD() {
		try {
		}
		catch (std::exception& e) {
			this->_logger.LogFatal("ANSFaceDetection::~ANSFaceDetection()", e.what(), __FILE__, __LINE__);
		}
	}
	bool ANSFD::Destroy() {
		try {
			return true;
		}
		catch (std::exception& e) {
			this->_logger.LogFatal("ANSFaceDetection::Destroy()", e.what(), __FILE__, __LINE__);
			return false;
		}

	}
}