using System;
using System.Collections;
using System.Collections.Generic;
using Plugins.JNGame.Sync.Frame.AStar.Entity;
using Plugins.JNGame.Sync.Frame.Entity;

namespace Plugins.JNGame.Sync.Frame.AStar.Processor
{
	public class PathProcessor
	{
		
		public event Action<JNPath> OnPathPreSearch;
		public event Action<JNPath> OnPathPostSearch;
		// public event Action OnQueueUnblocked;
		
		public LinkedList<JNPath> queue = new LinkedList<JNPath>();

		public JNAStarPath AStar;
		readonly PathReturnQueue returnQueue;
		
		readonly PathHandler[] pathHandlers;

		/// <summary>
		/// (帧同步无法使用原始的多线程 IEnumerator 可以 所以去除了多线程代码)
		/// 当不使用多线程时，IEnumerator 将存储在这里。  
		/// 如果不使用多线程，则使用协程来代替。协程不是通过 StartCoroutine 直接调用的，  
		/// 而是有一个单独的函数，该函数仅包含一个 while 循环，用于递增主要的 IEnumerator。  
		/// 这样做是为了让其他函数能够在任何时候推动线程向前，而无需等待 Unity 更新它。  
		/// 参见：CalculatePaths  
		/// 参见：CalculatePathsHandler  
		/// </summary>  
		IEnumerator threadCoroutine;
		
		/// <summary>  
		/// 保存下一个尚未被任何节点使用的节点索引。  
		/// 请参阅：nodeIndexPool  
		/// </summary>  
		int nextNodeIndex = 1;
		
		
		/// <summary>  
		/// 存储已被销毁的节点的索引。  
		/// 当节点频繁地被删除和创建时，为了避免破坏大量的内存结构，节点索引会被重新使用。  
		/// </summary>
		readonly Stack<int> nodeIndexPool = new Stack<int>();

		
		/// <summary>  
		/// 返回一个新的全局节点索引。  
		/// 警告：此方法不应直接调用。它仅由GraphNode构造函数使用。  
		/// </summary>  
		public int GetNewNodeIndex() {  
			// 检查节点索引池（nodeIndexPool）中是否有可用的索引  
			// 如果有，则从池中弹出一个索引并返回  
			// 如果没有，则增加下一个节点索引（nextNodeIndex）的值并返回  
			return nodeIndexPool.Count > 0 ? nodeIndexPool.Pop() : nextNodeIndex++;  
		}
		
		/// <summary>  
		/// 初始化节点的临时路径数据。  
		/// 警告：此方法不应直接调用。它仅由GraphNode构造函数使用。  
		/// </summary>  
		/// <param name="node">要初始化路径数据的节点</param>  
		public void InitializeNode(GraphNode node) {  
  
			// 遍历pathHandlers数组  
			for (int i = 0; i < pathHandlers.Length; i++) {  
				// 调用每个pathHandler的InitializeNode方法，传入要初始化的节点  
				pathHandlers[i].InitializeNode(node);  
			}  
  
			// 调用hierarchicalGraph的OnCreatedNode方法，通知它一个新的节点已被创建  
			AStar.hierarchicalGraph.OnCreatedNode(node);  
			
		}

		public PathProcessor(JNAStarPath AStar, PathReturnQueue returnQueue)
		{
			this.AStar = AStar;
			threadCoroutine = CalculatePaths(new PathHandler());
		}

		/// <summary>  
		/// 主要路径查找方法。  
		/// 该方法将在路径查找队列中计算路径。  
		///  
		/// 参考：CalculatePathsThreaded  
		/// 参考：StartPath  
		/// </summary>  
		IEnumerator CalculatePaths(PathHandler pathHandler)
		{
			// 允许的最大片数量
			// long maxTicks = 10;

			while (true)
			{
				// 当前正在计算的路径  
				JNPath p = null;

				// 尝试获取下一个要计算的路径  
				bool blockedBefore = false;
				while (p == null)
				{
					try
					{
						// 尝试从队列中获取路径，如果队列为空则不阻塞  
						if (queue.First != null)
						{
							p = queue.First.Value;
						}
						else p = null;
						queue.RemoveFirst();
						// 如果队列为空，则设置blockedBefore为true  
						blockedBefore |= p == null;
					}
					catch{
						// 如果队列被终止，则退出循环  
						yield break;
					}

					if (p == null)
					{
						// 如果路径为空，则yield，等待下一个帧  
						yield return null;
					}
				}

				// 将Path对象转换为IPathInternals接口  
				IPathInternals ip = (IPathInternals)p;

				// 准备路径的基础数据  
				ip.PrepareBase(pathHandler);

				// 将路径状态设置为Processing  
				ip.AdvanceState(PathState.Processing);

				// 调用一些回调函数  
				var tmpOnPathPreSearch = OnPathPreSearch;
				if (tmpOnPathPreSearch != null) tmpOnPathPreSearch(p);

				// // 记录路径开始计算的时间，用于计算计算时间  
				// long startTicks = System.DateTime.UtcNow.Ticks;
				// long totalTicks = 0;

				// 准备路径  
				ip.Prepare();

				// 检查Prepare调用是否导致路径完成  
				// 如果发生这种情况，通常表示路径计算失败  
				if (p.CompleteState == PathCompleteState.NotCalculated)
				{
					// // 为了调试目的，我们将最后计算的路径设置为p，以便我们可以在编辑器（场景视图）中查看其调试信息  
					// AStar.debugPathData = ip.PathHandler;
					// AStar.debugPathID = p.pathID;
					// 初始化路径，现在已准备好开始搜索  
					ip.Initialize();

					// 错误可能出现在Init函数中  
					while (p.CompleteState == PathCompleteState.NotCalculated)
					{
						// 对路径计算进行一些工作。  
						// 当花费的时间过多或计算完成时，该函数将返回  
						ip.CalculateStep();

						// 如果路径已完成计算，我们可以直接在这里中断，而不是休眠  
						// 这将提高延迟性能  
						if (p.CompleteState != PathCompleteState.NotCalculated) break;

						// yield/sleep以便其他线程可以工作  
						yield return null;

						// // 如果不再接受更多路径，则取消函数（以及相应的线程）  
						// // 这在A*对象即将被销毁时完成  
						// // 路径会被返回，然后该函数将被终止（在函数的更高位置有类似的IF语句）  
						// if (queue.IsTerminating)
						// {
						// 	p.FailWithError("AstarPath object destroyed");
						// }
						//
						// // 更新目标时间片，基于当前时间和最大时间片  
						// targetTick = System.DateTime.UtcNow.Ticks + maxTicks;
					}

					// // 将从路径开始计算到现在所花费的总时间片添加到总时间中，并转换为秒  
					// totalTicks += System.DateTime.UtcNow.Ticks - startTicks;
					// p.duration = totalTicks * 0.0001F;

#if ProfileAstar
		    // 如果启用了ProfileAstar，则增加已完成路径的计数  
		    System.Threading.Interlocked.Increment(ref AstarPath.PathsCompleted);
#endif

					// 清理节点标记和其他事情  
					ip.Cleanup();

					// 调用即时回调函数  
					// 需要将其存储在一个局部变量中以避免竞态条件  
					var tmpImmediateCallback = p.immediateCallback;
					if (tmpImmediateCallback != null) tmpImmediateCallback(p);

					// 调用路径搜索后的回调函数  
					// 需要将其存储在一个局部变量中以避免竞态条件  
					var tmpOnPathPostSearch = OnPathPostSearch;
					if (tmpOnPathPostSearch != null) tmpOnPathPostSearch(p);
					// 将路径推送到返回堆栈  
					// 它将被Unity的主线程检测到，并尽快返回（在下一个LateUpdate中）  
					returnQueue.Enqueue(p);

					// 将路径状态推进到返回队列中  
					ip.AdvanceState(PathState.ReturnQueue);

					// // 如果我们计算了大量的路径，则稍作等待  
					// if (System.DateTime.UtcNow.Ticks > targetTick)
					// {
					// 	// yield/sleep以便其他线程可以工作  
					// 	yield return null;
					// 	// 重置目标时间片为当前时间加上最大时间片  
					// 	targetTick = System.DateTime.UtcNow.Ticks + maxTicks;
					// }
					// yield/sleep以便其他线程可以工作  
					// yield return null;
				}
			}
		}
	}
}