#ifndef ANSWEBCAM_H
#define ANSWEBCAM_H
#define ANSWEBCAM_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <dshow.h>
#include <mutex>
#include <nvjpeg.h>
#include <cuda_runtime.h>
#include <turbojpeg.h>
#pragma comment(lib, "strmiids.lib")
#pragma comment(lib, "ole32.lib")

namespace ANSCENTER
{
	struct Resolution {
		int width;
		int height;

		Resolution(int w, int h) : width(w), height(h) {}

		int getArea() const {
			return width * height;
		}

		bool operator<(const Resolution& other) const {
			return getArea() < other.getArea();
		}
	};
	class ANSWEBCAM_API ANSWEBCAMPlayer
	{
	protected:
		// Add this structure definition in the private section
		cv::VideoCapture cap;
		int  _deviceId;
		int  _resWidth;
		int  _resHeight;
		int  _savedResWidth = 0;   // Saved resolution for stop/start restore
		int  _savedResHeight = 0;
		bool _enableMaxResolution = false; // false = Full HD default, true = max resolution
		int64_t _previousPTS;
		cv::Mat _previousImage;
		bool m_bPaused;
		std::string _lastJpegImage;
		bool		_isPlaying;
		std::vector<std::string> _cameraNames;
		int _imageRotateDeg = 0;
		std::recursive_mutex		_mutex;
		cv::Rect	 _bbox;
		bool		 _crop;
		EngineType		engineType;
		// Initialize nvJPEG structures
		nvjpegHandle_t nv_handle;
		nvjpegEncoderState_t nv_enc_state;
		nvjpegEncoderParams_t nv_enc_params;
		cudaStream_t stream;
		tjhandle _jpegCompressor;
	public:
		ANSWEBCAMPlayer();
		~ANSWEBCAMPlayer() noexcept;
		[[nodiscard]] bool Init(std::string licenseKey, std::string url);
		[[nodiscard]] bool Setup();
		[[nodiscard]] bool Reconnect();
		[[nodiscard]] bool Start();
		[[nodiscard]] bool IsPaused();
		[[nodiscard]] bool IsPlaying();
		[[nodiscard]] bool IsRecording();
		[[nodiscard]] bool Stop();
		void Destroy();
		void EnableAudio(bool status);
		void SetAudioVolume(int volume);
		[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
		[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
		[[nodiscard]] std::string GetJpegStringImage(int& width, int& height, int64_t& pts);
		[[nodiscard]] static std::string VectorToCommaSeparatedString(const std::vector<std::string>& inputVector);
		[[nodiscard]] static std::vector<std::string> ScanWebcamDevices();
		[[nodiscard]] static std::string GetSupportedResolutions(int deviceId);
		static std::mutex mtx;
		void SetImageRotate(int mode) {
			std::lock_guard<std::recursive_mutex> lock(_mutex);
			_imageRotateDeg = mode;
			if (mode > 360) _imageRotateDeg = 360;
		};
		void SetBBox(cv::Rect bbox);
		void SetCrop(bool crop);
		void SetDisplayResolution(int width, int height);  // Set display output size; 0,0 = original (no resize)
		[[nodiscard]] cv::Mat GetInferenceImage();  // Returns full-res frame for AI inference (no resize)
		cv::Mat _inferenceCloneCurr;   // Heap-cloned full-res (keeps data alive for registry)
		cv::Mat _inferenceClonePrev;   // Previous clone (keeps data alive during ANSRTYOLO read)
	public:
		void CheckLicense();
		SPDLogger& _logger = SPDLogger::GetInstance("ANSWebcamPlayer", false);
		bool            _licenseValid{ false };
		std::string     _licenseKey;
		
		// Resolution management methods
		std::vector<Resolution> GetAvailableResolutions(int deviceId);
		bool SetBestResolution(int deviceId);
		bool SetPreferredResolution(int deviceId);
		bool SetResolution(int width, int height);
		void SetEnableMaxResolution(bool enable);
		std::string GetAvailableResolutionsString(int deviceId);
	private:
		std::string encodeJpegString(const cv::Mat& img, int quality = 80);
		std::string encodeMatToJpegWithNvJPEG(const cv::Mat& inputMat, int quality = 80);
		void uploadPlanarBGRToGPU(const cv::Mat& inputMat, unsigned char** data);
		int _displayWidth = 0;   // 0 = no resize (return original)
		int _displayHeight = 0;
		cv::Mat _inferenceImage;  // Full-res frame for AI inference
	};
	std::mutex ANSWEBCAMPlayer::mtx;  // Definition of the static mutex
}
extern "C" __declspec(dllexport) int CreateANSWebcamPlayerHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle, const char* licenseKey, const char* url);
extern "C" __declspec(dllexport) int CreateANSWebcamPlayerWithMaxResoHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle, const char* licenseKey, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSWebcamPlayerHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int ScanANSWebcamPlayer(LStrHandle cameraNames);
extern "C" __declspec(dllexport) int ScanStrANSWebcamPlayer(std::vector<std::string> &cameraNameList);
extern "C" __declspec(dllexport) int GetWebcamImage(ANSCENTER::ANSWEBCAMPlayer * *Handle, int& width, int& height, int64_t & timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetWebcamStrImage(ANSCENTER::ANSWEBCAMPlayer * *Handle, int& width, int& height, int64_t & timeStamp, std::string & jpegImage);
extern "C" __declspec(dllexport) int GetWebcamCVImage(ANSCENTER::ANSWEBCAMPlayer** Handle, int& width, int& height, int64_t& timeStamp,  cv::Mat** image);
extern "C" __declspec(dllexport) int StartWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int ReconnectWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int StopWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int IsWebcamPlayerPaused(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int IsWebcamPlayerRunning(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int IsWebcamPlayerRecording(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) void SetWebcamPlayerAudioVolume(ANSCENTER::ANSWEBCAMPlayer * *Handle, int volume);
extern "C" __declspec(dllexport) void EnableWebcamPlayerAudioVolume(ANSCENTER::ANSWEBCAMPlayer * *Handle, int status);
extern "C" __declspec(dllexport) void SetWebcamImageRotation(ANSCENTER::ANSWEBCAMPlayer * *Handle, double rotationAngle);
extern "C" __declspec(dllexport) int  ScanSupportedResolutions(std::string cameraName,std::vector<std::string> cameraNameList, std::string &supportedResolution);
extern "C" __declspec(dllexport) int SetBBoxANSWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagANSWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetWebcamDisplayResolution(ANSCENTER::ANSWEBCAMPlayer** Handle, int width, int height);

#endif