using System;
using System.Collections.Generic;
using Game.Plugins.JNGame.Sync.Frame.AStar.Util;
using Plugins.JNGame.Sync.Frame.AStar.Entity;
using UnityEngine;
using Object = System.Object;

namespace Plugins.JNGame.Sync.Frame.AStar
{
    
    public delegate void OnPathDelegate(JNPath p);
    // public delegate void OnGraphDelegate(NavGraph graph);
    public delegate void OnScanDelegate(JNAStarPath script);
    
    /// <summary>  
    /// 具有从图空间到世界空间明确定义的变换的图  
    /// </summary>  
    public interface ITransformedGraph {  
        /// <summary>  
        /// 获取图的变换信息  
        /// </summary>  
        GraphTransform transform { get; }  
    }
    
    // /// <summary>Graph which supports the Linecast method</summary>
    // public interface IRaycastableGraph {
	   //  /// <summary>
	   //  /// Checks if the straight line of sight between the two points on the graph is obstructed.
	   //  ///
	   //  /// Returns: True if an obstacle was hit, and false otherwise.
	   //  /// </summary>
	   //  /// <param name="start">The start point of the raycast.</param>
	   //  /// <param name="end">The end point of the raycast.</param>
	   //  bool Linecast(Vector3 start, Vector3 end);
	   //  /// <summary>Deprecated:</summary>
	   //  bool Linecast(Vector3 start, Vector3 end, GraphNode hint);
	   //  /// <summary>Deprecated:</summary>
	   //  bool Linecast(Vector3 start, Vector3 end, GraphNode hint, out GraphHitInfo hit);
	   //  /// <summary>Deprecated:</summary>
	   //  bool Linecast(Vector3 start, Vector3 end, GraphNode hint, out GraphHitInfo hit, List<GraphNode> trace);
	   //  /// <summary>
	   //  /// Checks if the straight line of sight between the two points on the graph is obstructed.
	   //  ///
	   //  /// Returns: True if an obstacle was hit, and false otherwise.
	   //  /// </summary>
	   //  /// <param name="start">The start point of the raycast.</param>
	   //  /// <param name="end">The end point of the raycast.</param>
	   //  /// <param name="hit">Additional information about what was hit.</param>
	   //  /// <param name="trace">If you supply a list, it will be filled with all nodes that the linecast traversed. You may pass null if you don't care about this.</param>
	   //  /// <param name="filter">You may supply a callback to indicate which nodes should be considered unwalkable. Note that already unwalkable nodes cannot be made walkable in this way.</param>
	   //  bool Linecast(Vector3 start, Vector3 end, out GraphHitInfo hit, List<GraphNode> trace = null, System.Func<GraphNode, bool> filter = null);
    // }
    
    /// <summary>  
    /// 持有图形的位掩码。  
    /// 这个位掩码可以容纳最多32个图形。  
    ///  
    /// 位掩码可以隐式地转换为整数，也可以从整数隐式转换。.FromGraphName("My Other Grid Graph");  
    ///  
    /// NNConstraint nn = NNConstraint.Walkable;  
    ///  
    /// nn.graphMask = mask1 | mask2;  
    ///  
    /// // 查找与somePoint最近的节点，该节点位于'My Grid Graph'或'My Other Grid Graph'中  
    /// var info = AstarPath.active.GetNearest(somePoint, nn);  
    /// </code>  
    ///  
    /// 参见：位掩码（查看在线文档以获取工作链接）  
    /// </summary>  
    [Serializable]  
    public struct GraphMask {  
        
        /// <summary>表示掩码的位掩码</summary>  
        public int value;
        
        /// <summary>包含所有图形的掩码</summary>
        /// 这是一个静态属性，它返回一个包含所有图形的掩码。在二进制表示中，-1 的所有位都是 1，因此它表示所有图形。  
        public static GraphMask everything { get { return new GraphMask(-1); } }  
          
        public GraphMask(int value) {  
            this.value = value;  
        }  
          
        // 这是一个隐式转换运算符，它允许将 GraphMask 实例隐式转换为整数。转换的结果是 GraphMask 实例的 value 字段的值。  
        public static implicit operator int(GraphMask mask) {  
            return mask.value;  
        }  
          
          
        // 这是另一个隐式转换运算符，它允许将整数隐式转换为 GraphMask 实例。转换的结果是一个新的 GraphMask 实例，其 value 字段的值为传入的整数。  
        public static implicit operator GraphMask(int mask) {  
            return new GraphMask(mask);  
        }  
          
          
        /// <summary>组合两个掩码以形成它们之间的交集</summary>  
        /// 这是一个重载的按位与运算符，它接受两个 GraphMask 实例作为参数，并返回一个新的 GraphMask 实例，表示这两个掩码的交集。
        public static GraphMask operator &(GraphMask lhs, GraphMask rhs) {  
            return new GraphMask(lhs.value & rhs.value);  
        }  
            
          
        /// <summary>组合两个掩码以形成它们的并集</summary>  
        /// 这是一个重载的按位或运算符，它接受两个 GraphMask 实例作为参数，并返回一个新的 GraphMask 实例，表示这两个掩码的并集。  
        public static GraphMask operator |(GraphMask lhs, GraphMask rhs) {  
            return new GraphMask(lhs.value | rhs.value);  
        }  
          
          
        /// <summary>反转掩码</summary>  
        /// 这是一个重载的按位非运算符，它接受一个 GraphMask 实例作为参数，并返回一个新的 GraphMask 实例，表示该掩码的反转。  
        public static GraphMask operator ~(GraphMask lhs) {  
            return new GraphMask(~lhs.value);  
        }  
          
          
        /// <summary>如果此掩码包含具有给定图形索引的图形，则为真</summary>  
        /// 这是一个方法，它接受一个整数作为参数（表示图形索引），并返回一个布尔值，指示该掩码是否包含具有给定索引的图形。  
        /// 它通过将 value 字段右移 graphIndex 位，然后与 1 进行按位与运算，来检查特定位是否为 1。  
        public bool Contains(int graphIndex) {  
            return ((value >> graphIndex) & 1) != 0;  
        }  
          
          
        // /// <summary>包含给定图形的位掩码</summary>  
        // /// 这是一个静态方法，它接受一个 NavGraph 实例作为参数，并返回一个新的 GraphMask 实例，其中只有与给定图形的索引对应的位被设置为 1。  
        // /// 它通过将 1 左移 graph.graphIndex 位来创建这个掩码。  
        // public static GraphMask FromGraph(NavGraph graph) {  
        //     return 1 << (int)graph.graphIndex;  
        // }  
          
        // 这是 ToString 方法的重写，它返回 value 字段的字符串表示形式。这允许 GraphMask 实例以字符串形式输出，通常用于调试或日志记录。
        public override string ToString() {  
            return value.ToString();  
        }
        
        /// <summary>包含给定图形索引的位掩码。</summary>  
        /// 这是一个静态方法，它接受一个无符号整数（表示图形索引）作为参数，并返回一个GraphMask实例。  
        /// 它通过将1左移graphIndex位来创建一个位掩码，其中只有与给定索引对应的位被设置为1。  
        public static GraphMask FromGraphIndex(uint graphIndex) => new GraphMask(1 << (int)graphIndex);  
  
  
        // /// <summary>  
        // /// 包含具有给定名称的第一个图形的位掩码。FromGraphName("My Other Grid Graph");  
        // ///  
        // /// NNConstraint nn = NNConstraint.Walkable;  
        // ///  
        // /// nn.graphMask = mask1 | mask2;  
        // ///  
        // /// // 在'My Grid Graph'或'My Other Grid Graph'中找到离somePoint最近的节点  
        // /// var info = AstarPath.active.GetNearest(somePoint, nn);  
        // /// </code>  
        // /// </summary>  
        // /// 这是一个静态方法，它接受一个字符串（表示图形名称）作为参数，并返回一个GraphMask实例。  
        // /// 它首先尝试在活动的Astar数据集中找到具有给定名称的图形。  
        // /// 如果找到图形，它将使用FromGraph方法创建一个包含该图形的位掩码。  
        // /// 如果没有找到匹配的图形，它将抛出一个异常。
        // public static GraphMask FromGraphName(string graphName) {  
        //     // 尝试从活动数据集中找到具有给定名称的图形  
        //     var graph = AstarData.active.data.FindGraph(g => g.name == graphName);  
        //
        //     // 如果没有找到与名称匹配的图形，则抛出异常  
        //     if (graph == null)   
        //         throw new System.ArgumentException("Could not find any graph with the name '" + graphName + "'");  
        //
        //     // 如果找到了图形，使用FromGraph方法创建并返回一个包含该图形的位掩码  
        //     return FromGraph(graph);  
        // }  
        
    }
    
    /// <summary>  
    /// 最近节点约束。约束 <see cref="AstarPath.GetNearest"/> 函数返回的节点。  
    /// </summary>  
    public class NNConstraint {  
        
        /// <summary>  
        /// 可用于搜索的图。  
        /// 这是一个位掩码（bitmask），意味着位0指定是否应将图形列表中的第一个图形包含在搜索中，  
        /// 位1指定是否应将第二个图形包含在搜索中，依此类推。 GraphMask.FromGraphName("My Grid Graph");  
        /// GraphMask mask2 = GraphMask.FromGraphName("My Other Grid Graph");  
        ///  
        /// NNConstraint nn = NNConstraint.Walkable;  
        ///  
        /// nn.graphMask = mask1 | mask2;  
        ///  
        /// // 查找与somePoint最近的节点，该节点位于'My Grid Graph'或'My Other Grid Graph'中  
        /// var info = AstarPath.active.GetNearest(somePoint, nn);  
        /// </code>  
        ///  
        /// 注意：这仅影响从 <see cref="AstarPath.GetNearest"/> 调用返回的节点，  
        /// 如果一个有效的图通过节点链接连接到一个无效的图，则可能仍然会进行搜索。  
        ///  
        /// 参见：<see cref="AstarPath.GetNearest"/>  
        /// 参见：<see cref="SuitableGraph"/>  
        /// 参见：位掩码（在线文档中查看工作链接）  
        /// </summary>  
        public GraphMask graphMask = -1;  
        
        /// <summary>  
        /// 仅将区域 <see cref="area"/> 内的节点视为合适的。如果 <see cref="area"/> 小于 0（零），则不会影响任何内容。  
        /// </summary>  
        public bool constrainArea;
        
        /// <summary>  
        /// 一个NNConstraint，用于过滤掉不可通过的节点。  
        /// 这是最常用的NNConstraint。  
        ///  
        /// 它还约束最近节点必须在A* Inspector -> Settings -> Max Nearest Node Distance设置的最大距离内。  
        /// </summary>  
        public static NNConstraint Walkable {  
            get {  
                return new NNConstraint();  
            }  
        }
    }
    
    /// <summary>  
    /// 一个特殊的NNConstraint，可以在路径中的起始节点和结束节点使用不同的逻辑。  
    /// PathNNConstraint可以被分配给Path.nnConstraint字段，路径将首先搜索起始节点，然后它将调用<see cref="SetStart"/>并继续搜索结束节点（对于MultiTargetPath，则是多个节点）。  
    /// 默认的PathNNConstraint将约束终点位于与起点相同的区域内。  
    /// </summary>  
    public class PathNNConstraint : NNConstraint {  
        
        // // 定义了一个静态的默认PathNNConstraint实例，该实例在创建时默认将constrainArea设置为true  
        // public static new PathNNConstraint Default {  
        //     get {  
        //         return new PathNNConstraint {  
        //             constrainArea = true  
        //         };  
        //     }  
        // }  
        //
        // /// <summary>在找到起始节点后被调用。这用于在路径中的起始节点和结束节点使用不同的搜索逻辑</summary>  
        // /// <param name="node">找到的起始节点</param>  
        // public virtual void SetStart (GraphNode node) {  
        //     // 如果找到的节点不为空，则设置area为节点的Area属性值  
        //     if (node != null) {  
        //         area = (int)node.Area;  
        //     } else {  
        //         // 如果节点为空，则禁用区域约束  
        //         constrainArea = false;  
        //     }  
        // } 
        
    }
    
    /// <summary>  
    /// 路径请求的状态  
    /// </summary>  
    public enum PathCompleteState {  
        /// <summary>  
        /// 路径尚未计算。  
        /// 请参考：<see cref="Pathfinding.Path.IsDone()"/>  
        /// </summary>  
        NotCalculated = 0,  
      
        /// <summary>  
        /// 路径计算已完成，但失败了。  
        /// 请参考：<see cref="Pathfinding.Path.error"/>  
        /// </summary>  
        Error = 1,  
      
        /// <summary>  
        /// 路径已成功计算  
        /// </summary>  
        Complete = 2,  
      
        /// <summary>  
        /// 路径已计算，但只找到了部分路径。  
        /// 请参考：<see cref="Pathfinding.ABPath.calculatePartial"/>  
        /// </summary>  
        Partial = 3,  
    }
    
    /// <summary>
	/// Integer Rectangle.
	/// Uses an inclusive coordinate range.
	///
	/// Works almost like UnityEngine.Rect but with integer coordinates
	/// </summary>
	[Serializable]
	public struct IntRect {
		public int xmin, ymin, xmax, ymax;

		public IntRect (int xmin, int ymin, int xmax, int ymax) {
			this.xmin = xmin;
			this.xmax = xmax;
			this.ymin = ymin;
			this.ymax = ymax;
		}

		public bool Contains (int x, int y) {
			return !(x < xmin || y < ymin || x > xmax || y > ymax);
		}

		public Int2 Min {
			get {
				return new Int2(xmin, ymin);
			}
		}

		public Int2 Max {
			get {
				return new Int2(xmax, ymax);
			}
		}

		public int Width {
			get {
				return xmax-xmin+1;
			}
		}

		public int Height {
			get {
				return ymax-ymin+1;
			}
		}

		public int Area {
			get {
				return Width * Height;
			}
		}

		/// <summary>
		/// Returns if this rectangle is valid.
		/// An invalid rect could have e.g xmin > xmax.
		/// Rectamgles with a zero area area invalid.
		/// </summary>
		public bool IsValid () {
			return xmin <= xmax && ymin <= ymax;
		}

		public static bool operator == (IntRect a, IntRect b) {
			return a.xmin == b.xmin && a.xmax == b.xmax && a.ymin == b.ymin && a.ymax == b.ymax;
		}

		public static bool operator != (IntRect a, IntRect b) {
			return a.xmin != b.xmin || a.xmax != b.xmax || a.ymin != b.ymin || a.ymax != b.ymax;
		}

		public override bool Equals (Object obj) {
			var rect = (IntRect)obj;

			return xmin == rect.xmin && xmax == rect.xmax && ymin == rect.ymin && ymax == rect.ymax;
		}

		public override int GetHashCode () {
			return xmin*131071 ^ xmax*3571 ^ ymin*3109 ^ ymax*7;
		}

		/// <summary>
		/// Returns the intersection rect between the two rects.
		/// The intersection rect is the area which is inside both rects.
		/// If the rects do not have an intersection, an invalid rect is returned.
		/// See: IsValid
		/// </summary>
		public static IntRect Intersection (IntRect a, IntRect b) {
			return new IntRect(
				Math.Max(a.xmin, b.xmin),
				Math.Max(a.ymin, b.ymin),
				Math.Min(a.xmax, b.xmax),
				Math.Min(a.ymax, b.ymax)
				);
		}

		/// <summary>Returns if the two rectangles intersect each other</summary>
		public static bool Intersects (IntRect a, IntRect b) {
			return !(a.xmin > b.xmax || a.ymin > b.ymax || a.xmax < b.xmin || a.ymax < b.ymin);
		}

		/// <summary>
		/// Returns a new rect which contains both input rects.
		/// This rectangle may contain areas outside both input rects as well in some cases.
		/// </summary>
		public static IntRect Union (IntRect a, IntRect b) {
			return new IntRect(
				Math.Min(a.xmin, b.xmin),
				Math.Min(a.ymin, b.ymin),
				Math.Max(a.xmax, b.xmax),
				Math.Max(a.ymax, b.ymax)
				);
		}

		/// <summary>Returns a new IntRect which is expanded to contain the point</summary>
		public IntRect ExpandToContain (int x, int y) {
			return new IntRect(
				Math.Min(xmin, x),
				Math.Min(ymin, y),
				Math.Max(xmax, x),
				Math.Max(ymax, y)
				);
		}

		/// <summary>Returns a new rect which is expanded by range in all directions.</summary>
		/// <param name="range">How far to expand. Negative values are permitted.</param>
		public IntRect Expand (int range) {
			return new IntRect(xmin-range,
				ymin-range,
				xmax+range,
				ymax+range
				);
		}

		public override string ToString () {
			return "[x: "+xmin+"..."+xmax+", y: " + ymin +"..."+ymax+"]";
		}

		/// <summary>Draws some debug lines representing the rect</summary>
		public void DebugDraw (GraphTransform transform, Color color) {
			Vector3 p1 = transform.Transform(new Vector3(xmin, 0, ymin));
			Vector3 p2 = transform.Transform(new Vector3(xmin, 0, ymax));
			Vector3 p3 = transform.Transform(new Vector3(xmax, 0, ymax));
			Vector3 p4 = transform.Transform(new Vector3(xmax, 0, ymin));

			Debug.DrawLine(p1, p2, color);
			Debug.DrawLine(p2, p3, color);
			Debug.DrawLine(p3, p4, color);
			Debug.DrawLine(p4, p1, color);
		}
	}
    
    /// <summary>  
    /// 路径在管道中的内部状态  
    /// </summary>  
    public enum PathState {  
        /// <summary>  
        /// 路径已创建但尚未安排  
        /// </summary>  
        Created = 0,  
      
        /// <summary>  
        /// 路径正在等待计算  
        /// </summary>  
        PathQueue = 1,  
      
        /// <summary>  
        /// 路径正在计算中  
        /// </summary>  
        Processing = 2,  
      
        /// <summary>  
        /// 路径已计算完成，正在等待调用回调函数  
        /// </summary>  
        ReturnQueue = 3,  
      
        /// <summary>  
        /// 目前正在调用路径的回调函数（仅在回调函数内部设置）  
        /// </summary>  
        Returning = 4,  
      
        /// <summary>  
        /// 路径已计算完成且回调函数已调用  
        /// </summary>  
        Returned = 5,  
    }
    
}