#ifndef ANSVIDEOPLAYER_H
#define ANSVIDEOPLAYER_H
#define ANSVIDEOPLAYER_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 <thread>
#include <chrono>
#include <atomic>
#include <turbojpeg.h>
#include "file_player.h"     // CFilePlayer (FFmpeg HW decode: CUDA/D3D11VA/DXVA2)
#include "video_decoder.h"   // HW_DECODING_AUTO, HWDecoderPool

namespace ANSCENTER
{
	class ANSVIDEOPLAYER_API ANSVIDEOPLAYER
	{
	protected:
		cv::VideoCapture cap;
		int  _resWidth;
		int  _resHeight;
		int64_t  _totalFrames;
		int64_t  _currentFrame;
		int64_t  _previousPTS;
		double _fps;
		bool		_isPlaying;
		std::string _lastJpegImage;
		cv::Mat _previousImage;
		bool m_bPaused;
		int _imageRotateDeg = 0;
		std::string  _url;
		cv::Rect	 _bbox;
		bool		 _crop;
		std::recursive_mutex		_mutex;
		std::mutex _cvMutex;
		std::condition_variable _cv;
		tjhandle _jpegCompressor;

	public:
		// --- HW decode state (CFilePlayer composition) ---
		// Public: accessed by extern "C" GetVideoPlayerCVImage for NV12/CUDA registry attachment
		std::unique_ptr<CFilePlayer> _hwPlayer;    // HW decode path (nullptr = CV fallback)
		bool _hwDecodeActive = false;              // true when _hwPlayer init succeeded
		int  _hwGpuIndex = -1;                     // GPU index for registry (-1 = CPU only)
		bool _hwCudaAccel = false;                 // true = NVIDIA CUDA zero-copy available
		bool _hwEOF = false;                       // true when video reached end of file
		int64_t _hwFrameCount = 0;                 // frame counter for EOF detection
		int64_t _hwLastPts = 0;                    // last video PTS for EOF wrap detection
		ANSVIDEOPLAYER();
		~ANSVIDEOPLAYER() 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();
		void SetBBox(cv::Rect bbox);
		void SetCrop(bool crop);
		[[nodiscard]] bool Stop();
		void Destroy();
		void EnableAudio(bool status);
		void SetAudioVolume(int volume);
		void SetImageRotate(int mode) {
			std::lock_guard<std::recursive_mutex> lock(_mutex);
			_imageRotateDeg = mode;
			if (mode > 360) _imageRotateDeg = 360;
		};
		[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
		[[nodiscard]] cv::Mat GetInferenceImage();  // Returns full-res frame for AI inference (no resize/rotation)
		[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
		[[nodiscard]] std::string GetJpegStringImage(int& width, int& height, int64_t& pts);
		void SetDisplayResolution(int width, int height);  // Set display output size; 0,0 = original (no resize)
	public:
		void CheckLicense();
		SPDLogger& _logger = SPDLogger::GetInstance("ANSVideoPlayer", false);
		bool            _licenseValid{ false };
		//std::once_flag	licenseOnceFlag;
		std::string     _licenseKey;
		cv::Mat _inferenceCloneCurr;   // Heap-cloned full-res (keeps data alive for registry)
		cv::Mat _inferenceClonePrev;   // Previous clone (keeps data alive during ANSRTYOLO read)
	private:
		std::string encodeJpegString(const cv::Mat& img, int quality = 80);
		int _displayWidth = 0;   // 0 = no resize (return original)
		int _displayHeight = 0;
		cv::Mat _inferenceImage;       // Full-res frame for AI inference
	};
}
extern "C" __declspec(dllexport) int CreateANSVideoPlayerHandle(ANSCENTER::ANSVIDEOPLAYER** Handle, const char* licenseKey, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSVideoPlayerHandle(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int GetVideoPlayerImage(ANSCENTER::ANSVIDEOPLAYER** Handle, int& width, int& height, int64_t& timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetVideoPlayerStrImage(ANSCENTER::ANSVIDEOPLAYER** Handle, int& width, int& height, int64_t& timeStamp, std::string& jpegImage);
extern "C" __declspec(dllexport) int GetVideoPlayerCVImage(ANSCENTER::ANSVIDEOPLAYER** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int ReconnectVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int StopVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int IsVideoPlayerPaused(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int IsVidedoPlayerRunning(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int IsVideoPlayerRecording(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) void SetVideoPlayerAudioVolume(ANSCENTER::ANSVIDEOPLAYER** Handle, int volume);
extern "C" __declspec(dllexport) void EnableVideoPlayerAudioVolume(ANSCENTER::ANSVIDEOPLAYER** Handle, int status);
extern "C" __declspec(dllexport) void SetVideoPlayerImageRotation(ANSCENTER::ANSVIDEOPLAYER** Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetVideoPlayerDisplayResolution(ANSCENTER::ANSVIDEOPLAYER** Handle, int width, int height);
#endif