using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;
using SLAMUVC;
using UnityEngine.UI;
using System.Collections.Generic;
using AOT;
using System.Threading;
using UnityEngine.Events;
using UnityEngine.Android;

namespace SLAMUVC
{
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	public struct UVCCtrlInfo
	{
		public string name;
		public Int32 current;
		public Int32 min;
		public Int32 max;
		public Int32 def;

		public override string ToString()
		{
			return $"{base.ToString()}(name={name},min={min},max={max},def={def},current={current})";
		}
	}

	[System.Serializable]
	public class UVCCtrl
	{
		public string name;
		public bool isAuto;
		public bool isEnable;
		public int[] limit;
		public int value;
	}
	[System.Serializable]
	public class UVCCtrlWrapper
	{
		public UVCCtrl[] uvcCtrls;
	}
	public enum CameraFormat
	{
		MJPEG,
		YUV,
	}
	public enum CameraMirror
	{
		NONE,
		HORIZONTAL,//水平翻转
		VERTICAL//垂直翻转
	}
	public enum UVCCameraPixelFormat
	{
		PIXEL_FORMAT_RAW,
		PIXEL_FORMAT_YUV,
		PIXEL_FORMAT_NV12, // one format of YUV420SemiPlanar
		PIXEL_FORMAT_NV21, // one format of YUV420SemiPlanar
		PIXEL_FORMAT_RGB,
		PIXEL_FORMAT_RGB565,
		PIXEL_FORMAT_RGBX
	}
	//UVC的管理类
	public class UVCInterface : MonoBehaviour
	{
		private const string UVC_MANAGER = "com.slambb.myuvc.MyUVCManager";
		//java对象
		private AndroidJavaObject uvcManagerObj = null;

		CameraFormat mCameraFormat = CameraFormat.MJPEG;
		CameraMirror mCameraMirror = CameraMirror.VERTICAL;//默认垂直
		int Width = 1280;
		int Height = 720;
		Texture2D _cameraTexture;
		public Texture2D CameraTexture => _cameraTexture;

		private UVCCtrl[] uvcCtrls;
		public UVCCtrl[] UVCCtrls => uvcCtrls;


		private SynchronizationContext mainContext;

		/// <summary>
		/// 初始化相机权限成功
		/// </summary>
		public CameraPermissionHandle systemCameraPermissionHandle;
		public delegate void CameraPermissionHandle();
		/// <summary>
		/// 纹理更新事件
		/// </summary>
		public CameraTextureHandle cameraTextureHandle;
		public delegate void CameraTextureHandle();



		private static readonly string ActivityClassName = "com.slambb.myuvc.UsbPermissionActivity";

		//public void RequestUsbPermission()
		//{
		//	using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
		//	{
		//		AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
		//		AndroidJavaClass usbPermissionActivity = new AndroidJavaClass(ActivityClassName);

		//		// Start UsbPermissionActivity
		//		activity.Call("startActivity", usbPermissionActivity.CallStatic<AndroidJavaObject>("newIntent", activity));
		//	}
		//}

		void Awake()
		{
			try
			{
				// 创建 uvcManagerObj 对象
				uvcManagerObj = new AndroidJavaObject(UVC_MANAGER);

			}
			catch (Exception e)
			{
				Debug.LogError("UVC_MANAGER Exception: " + e.Message);
			}

			//RequestUsbPermission();
		}

		void Start()
		{

			OpenCameraPermisson();
		}

		private void OnDestroy()
		{
			Remove(this);
			uvcManagerObj.Call("clearCameraHelper");

		}
		/// <summary>
		/// 创建一个纹理id到插件
		/// </summary>
		private void CreateTextureAndPassToPlugin()
		{
			// 销毁纹理
			if (_cameraTexture != null)
			{
				Destroy(_cameraTexture);
				_cameraTexture = null;
			}
			// Create a texture
			Texture2D tex = new Texture2D(Width, Height, TextureFormat.ARGB32, false);
			// 设置点过滤，以便我们可以清楚地看到像素
			tex.filterMode = FilterMode.Point;
			// 调用Apply()，使其实际上传到GPU
			tex.Apply();
			_cameraTexture = tex;
			//将纹理指针传递给插件
			SetTexture(tex.GetNativeTexturePtr(), tex.width, tex.height);

			cameraTextureHandle?.Invoke();
		}
		//private IEnumerator CallPluginAtEndOfFrames()
		//{
		//	while (true)
		//	{
		//		//等待所有帧渲染完成
		//		yield return new WaitForEndOfFrame();
		//		//发出具有任意整数标识符的插件事件。
		//		//该插件可以区分不同的
		//		//它需要根据这个ID做的事情。
		//		//对于我们的简单插件，我们在这里传递哪个ID并不重要。
		//		if(GetIsPreviewing()) GL.IssuePluginEvent(GetRenderEventFunc(), 1);
		//	}
		//}
		/// <summary>
		/// 更新纹理
		/// </summary>
		/// <param name="width"></param>
		/// <param name="height"></param>
		/// <param name="bUpdate"></param>
		public void OnTextureUpdate(int width, int height, bool bUpdate)
		{

			mainContext.Post(__ =>
			{
				if (bUpdate)
				{
					Debug.Log("创建新纹理：size=[" + width + "," + height + "]");
					Width = width;
					Height = height;
					CreateTextureAndPassToPlugin();
				}
				else
				{
					GL.IssuePluginEvent(GetRenderEventFunc(), 1);
				}

			}, null);
		}
		public bool GetIsPreviewing()
		{
			if (uvcManagerObj != null)
			{
				if (uvcManagerObj.Call<int>("GetIsPreviewing") == 1)
				{
					return true;
				}
			}

			return false;
		}
		/// <summary>
		/// 初始化相机和对应的操作，初始化后会自动打开相机
		/// </summary>
		/// <param name="width"></param>
		/// <param name="height"></param>
		public void InitCamera(int width, int height)
		{
			Width = width;
			Height = height;
			uvcManagerObj.Call("initCameraHelper", Width, Height, mCameraFormat.ToString(), mCameraMirror.ToString());
			//主线程
			mainContext = SynchronizationContext.Current;
			//注册c回调
			Add(this);
			//mainContext.Post(__ =>
			//{
			//	//CreateTextureAndPassToPlugin();
			//}, null);
			//StartCoroutine("CallPluginAtEndOfFrames");
		}

		public void OpenCamera()
		{
			uvcManagerObj.Call("OpenCamera");
		}
		public void CloseCamera()
		{
			uvcManagerObj.Call("CloseCamera");
		}
		public void ChangeCameraInfo(int width, int height)
		{
			uvcManagerObj.Call("ChangeCameraInfo", width, height, mCameraFormat.ToString());
		}
		public string[] GetSupportedResolutions()
		{
			if (uvcManagerObj != null)
			{
				var objPtr = uvcManagerObj.Call<AndroidJavaObject>("GetSupportedResolutions").GetRawObject();

				if (objPtr != IntPtr.Zero)
					return AndroidJNIHelper.ConvertFromJNIArray<string[]>(objPtr);
			}

			return null;
		}

		/// <summary>
		/// 水平翻转
		/// </summary>
		public void FlipHorizontally()
		{
			uvcManagerObj.Call("FlipHorizontally");
		}

		/// <summary>
		/// 垂直翻转
		/// </summary>
		public void FlipVertically()
		{
			uvcManagerObj.Call("FlipVertically");
		}
		public void resetControlParams()
		{
			uvcManagerObj.Call("resetControlParams");
		}
		public void GetUvcCtrlList()
		{

			if (uvcManagerObj != null)
			{
				string json = uvcManagerObj.Call<string>("GetUvcCtrlList");

				UVCCtrlWrapper wrapper = JsonUtility.FromJson<UVCCtrlWrapper>("{\"uvcCtrls\":" + json + "}");
				if (wrapper != null && wrapper.uvcCtrls != null)
				{

					//赋值
					uvcCtrls = wrapper.uvcCtrls;

					//foreach (UVCCtrl ctrl in wrapper.uvcCtrls)
					//{
					//	Debug.Log($"name:{ctrl.name}, isAuto: {ctrl.isAuto}, isEnable: {ctrl.isEnable}, limit: {string.Join(", ", ctrl.limit)}, value: {ctrl.value}");
					//}
				}
				else
				{
					Debug.LogError("Failed to parse JSON data.");
				}
			}


		}
		public void SetBrightness(int value)
		{
			uvcManagerObj.Call("SetBrightness", value);
		}
		public void SetContrast(int value)
		{
			uvcManagerObj.Call("SetContrast", value);
		}

		public int SetCtrlValue(string type, Int32 value)
		{
			int result = -1;
			if (type == "PU_BRIGHTNESS")
			{
				uvcManagerObj.Call("SetBrightness", value);
				result = 0;
			}
			else if (type == "PU_CONTRAST")
			{
				uvcManagerObj.Call("SetContrast", value);
				result = 0;
			}
			return result;
		}

		//--------------------------------------------------------------------------------
		/**
		 * 先处理相机权限
		*/
		private void OpenCameraPermisson()
		{

			if (Permission.HasUserAuthorizedPermission(Permission.Camera))
			{
				Debug.LogError("HasUserAuthorizedPermission！");
				systemCameraPermissionHandle?.Invoke();
				return;
			}

			bool useCallbacks = true;
			if (!useCallbacks)
			{
				// We do not have permission to use the microphone.
				// Ask for permission or proceed without the functionality enabled.
				Permission.RequestUserPermission(Permission.Camera);
			}
			else
			{
				var callbacks = new PermissionCallbacks();
				callbacks.PermissionDenied += PermissionCallbacks_PermissionDenied;
				callbacks.PermissionGranted += PermissionCallbacks_PermissionGranted;
				callbacks.PermissionDeniedAndDontAskAgain += PermissionCallbacks_PermissionDeniedAndDontAskAgain;
				Permission.RequestUserPermission(Permission.Camera, callbacks);
			}
		}


		void PermissionCallbacks_PermissionDenied(string PermissionName)
		{
			Debug.LogError($"PermissionCallbacks_PermissionDenied[{PermissionName}]");
		}

		//本次允许
		void PermissionCallbacks_PermissionGranted(string PermissionName)
		{
			Debug.Log($"PermissionCallbacks_PermissionGranted[{PermissionName}]");
			systemCameraPermissionHandle?.Invoke();
		}
		void PermissionCallbacks_PermissionDeniedAndDontAskAgain(string PermissionName)
		{
			Debug.Log($"PermissionCallbacks_PermissionDeniedAndDontAskAgain[{PermissionName}]");
			systemCameraPermissionHandle?.Invoke();
		}

		//设置GL纹理
		[DllImport("TransferTexture")]
		private static extern void SetTexture(IntPtr texture, int w, int h);
		//GL渲染事件
		[DllImport("TransferTexture")]
		private static extern IntPtr GetRenderEventFunc();


		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		public delegate void TextureUpdateDelegate(Int32 id, int width, int height, bool bUpdate);

		[DllImport("TransferTexture")]
		private static extern void RegisterTextureUpdateCallback(Int32 id, TextureUpdateDelegate callback);
		[DllImport("TransferTexture")]
		private static extern void UnregisterTextureUpdateCallback(Int32 id, TextureUpdateDelegate callback);
		//记录MyUVCInterface
		private static Dictionary<Int32, UVCInterface> mUVCInterfaces = new Dictionary<Int32, UVCInterface>();

		private static TextureUpdateDelegate textureUpdateDelegate;
		//注册回调事件
		public static void Add(UVCInterface myUVCInterface)
		{
			Int32 id = myUVCInterface.GetHashCode();
			textureUpdateDelegate = new TextureUpdateDelegate(TextureUpdateHandler);
			mUVCInterfaces.Add(id, myUVCInterface);
			RegisterTextureUpdateCallback(id, textureUpdateDelegate);
		}
		//移除回调事件
		public static void Remove(UVCInterface myUVCInterface)
		{
			Int32 id = myUVCInterface.GetHashCode();
			UnregisterTextureUpdateCallback(id, textureUpdateDelegate);
			mUVCInterfaces.Remove(id);
		}
		//数据更新时候回调
		[MonoPInvokeCallback(typeof(TextureUpdateDelegate))]
		private static void TextureUpdateHandler(Int32 id, int width, int height, bool bUpdate)
		{
			var myUVCInterface = mUVCInterfaces.ContainsKey(id) ? mUVCInterfaces[id] : null;
			if (myUVCInterface != null)
			{
				myUVCInterface.OnTextureUpdate(width, height, bUpdate);
			}
		}

	}
}