using System.Collections;
using System.Collections.Generic;
using Game.Plugins.App.Sync;
using Game.Plugins.JNGame.Sync.Frame.AStar.Util;
using Game.Plugins.JNGame.Sync.Frame.AstarPath.AI;
using Game.Plugins.JNGame.Sync.Frame.AstarPath.RVO;
using Plugins.JNGame.Sync.Frame.AStar;
using Plugins.JNGame.Sync.Frame.game.Time;
using Plugins.JNGame.Util;
using UnityEngine;

public class GRVO02WorldPlayerController : JNGSyncFrameDefault
{
    //模式
    public GRVO02WorldMode mode;
    
    //添加寻路AI
    private JNAISeeker ai;
    //添加RVO避障 控制器 (里面默认使用避障)
    private JNRVOController rvo;
    
    //目标位置
    private Vector3 target;
    
    //是否正在查询位置
    private bool canSearchAgain = true;
    
    //当前路径
    private JNPath path = null;
    
    // 向量路径  
    List<Vector3> vectorPath;
    // waypoint进度  
    private int wp = 0;
    
    //移动距离
    public float moveNextDist = 1;
    
    //下一次寻路 (主要目的是为了在寻路过程中引入一定的随机性和变化，特别是在动态环境或者存在移动障碍物的场景中。这样的设计可以帮助代理（例如游戏中的角色）更加智能和灵活地适应环境的变化 )
    //如果不重新计算路径，代理可能会遇到障碍物而停止移动，或者沿着一条不再是最佳（甚至不再可通行）的路径移动
    public float nextRepath = 1;
    
    //平滑停止
    public float slowdownDistance = 1;
    
    //最大速度
    public float maxSpeed = 10;
    
    //碰撞层级
    public LayerMask groundMask;

    public override void OnSyncLoad()
    {
        base.OnSyncLoad();
        //初始化寻路AI
        ai = new JNAISeeker(mode.AStar);
        //初始化避障控制器
        rvo = new JNRVOController(mode.Simulator,gameObject);
    }

    //设置移动位置
    public void SetTarget (Vector3 target) {
        this.target = target;
        RecalculatePath();
    }
    
    /// 重新计算到达目标点的路径 
    public void RecalculatePath() {  
        //不允许再次搜索路径
        canSearchAgain = false;
        //下一次寻路时间
        nextRepath = GetSync().Time.time + 2;
        // 启动路径搜索，传入当前位置、目标位置和路径搜索完成的回调函数  
        ai.StartPath(transform.position, target, OnPathComplete);  
    }
    
    /// <summary>  
    /// 路径搜索完成时的回调函数  
    /// <param name="_p">搜索得到的路径</param>  
    public void OnPathComplete(JNPath _p) {  
        // 将传入的路径尝试转换为ABPath类型  
        JNABPath p = _p as JNABPath;  
  
        // 允许再次搜索路径  
        canSearchAgain = true;  
  
        // 如果之前存在路径对象，则释放对它的引用  
        if (path != null) path.Release(this);  
  
        // 更新当前路径对象为搜索得到的新路径  
        path = p;  
  
        // 声明对该路径的所有权  
        p.Claim(this);  
  
        // 如果路径搜索出错（比如没有找到可行路径）  
        if (p.error) {  
            //重置数据
            // 重置waypoint进度  
            wp = 0;  
            // 清空向量路径  
            vectorPath = null;  
            // 提前返回，不再继续执行后续代码  
            return;  
        }  
  
        // 获取路径的起始点  
        Vector3 p1 = p.originalStartPoint;  
        // 获取代理当前的位置  
        Vector3 p2 = transform.position;  
        // 将起始点的y坐标设置为当前位置的y坐标，确保路径在同一水平面上  
        p1.y = p2.y;  
        // 计算当前位置与起始点之间的距离  
        float d = (p2 - p1).magnitude;  
        // 重置waypoint进度  
        wp = 0;  
  
        // 更新向量路径为搜索得到的新路径的向量表示  
        vectorPath = p.vectorPath;  
        Vector3 waypoint; // 用于存储当前waypoint的位置  
  
        // 如果定义了每次移动的最大距离（moveNextDist > 0）  
        if (moveNextDist > 0) {  
            // 遍历从起始点到当前位置的距离，每次增加moveNextDist的60%  
            for (float t = 0; t <= d; t += moveNextDist * 0.6f) {  
                // 递减waypoint索引，因为我们是从路径的末尾开始向前遍历  
                wp--;  
                // 计算当前位置的向量表示  
                Vector3 pos = p1 + (p2 - p1) * t;  
  
                // 循环遍历向量路径，直到找到一个waypoint，使得代理从当前位置移动到该waypoint的距离  
                // 大于或等于moveNextDist，或者已经到达向量路径的最后一个waypoint  
                do {  
                    // 递增waypoint索引  
                    wp++;  
                    // 获取向量路径中当前waypoint的位置  
                    waypoint = vectorPath[wp];  
                    // 循环条件：代理到当前waypoint的距离小于moveNextDist，并且还没有到达向量路径的最后一个waypoint  
                } while (rvo.To2D(pos - waypoint).sqrMagnitude < moveNextDist * moveNextDist && wp != vectorPath.Count - 1);  
            }  
        }
        
    }

    public override void OnSyncUpdate(int dt, JNFrameInfo frame, Object input)
    {
        base.OnSyncUpdate(dt, frame, input);
        
         // 检查是否需要重新计算路径  
        if (GetSync().Time.time >= nextRepath && canSearchAgain)  
        {  
            RecalculatePath();  
        }  
      
        Vector3 pos = transform.position;  
      
        // 如果存在路径且路径不为空  
        if (vectorPath != null && vectorPath.Count != 0)  
        {  
            // 遍历路径直到找到下一个要到达的点  
            while ((rvo.To2D(pos - vectorPath[wp]).sqrMagnitude < moveNextDist * moveNextDist && wp != vectorPath.Count - 1) || wp == 0)  
            {  
                wp++;  
            }  
      
            // 计算路径段上的点  
            var p1 = vectorPath[wp - 1];  
            var p2 = vectorPath[wp];  
            var t = VectorMath.LineCircleIntersectionFactor(rvo.To2D(transform.position), rvo.To2D(p1), rvo.To2D(p2), moveNextDist);  
            t = Mathf.Clamp01(t);  
            Vector3 waypoint = Vector3.Lerp(p1, p2, t);  
      
            // 计算到路径终点的剩余距离  
            float remainingDistance = rvo.To2D(waypoint - pos).magnitude + rvo.To2D(waypoint - p2).magnitude;  
            for (int i = wp; i < vectorPath.Count - 1; i++)  
            {  
                remainingDistance += rvo.To2D(vectorPath[i + 1] - vectorPath[i]).magnitude;  
            }  
      
            // 设置目标点和期望速度  
            var rvoTarget = (waypoint - pos).normalized * remainingDistance + pos;  
            var desiredSpeed = Mathf.Clamp01(remainingDistance / slowdownDistance) * maxSpeed;  
      
            // // 绘制一条从当前位置到路径点的红色线段用于调试  
            // Debug.DrawLine(transform.position, waypoint, Color.red);  
      
            // 设置RVO控制器的目标点和速度  
            rvo.SetTarget(rvoTarget, desiredSpeed, maxSpeed);  
        }  
        else  
        {  
            // 如果没有路径，则静止不动  
            rvo.SetTarget(pos, maxSpeed, maxSpeed);  
        }  
      
        // 从RVO控制器获取处理过的移动增量并移动角色  
        var movementDelta = rvo.CalculateMovementDelta(Time.deltaTime);  
        pos += movementDelta;  
      
        // 如果移动增量足够大，则旋转角色以面向移动方向  
        if (Time.deltaTime > 0 && movementDelta.magnitude / Time.deltaTime > 0.01f)  
        {  
            var rot = transform.rotation;  
            var targetRot = Quaternion.LookRotation(movementDelta, rvo.To3D(Vector2.zero, 1));  
            const float RotationSpeed = 5;  
            if (rvo.movementPlane == MovementPlane.XY)  
            {  
                targetRot = targetRot * Quaternion.Euler(-90, 180, 0);  
            }  
            transform.rotation = Quaternion.Slerp(rot, targetRot, Time.deltaTime * RotationSpeed);  
        }  
      
        // 如果角色在XZ平面上移动，确保它保持在地面上  
        if (rvo.movementPlane == MovementPlane.XZ)  
        {  
            RaycastHit hit;  
            if (Physics.Raycast(pos + Vector3.up, Vector3.down, out hit, 2, groundMask))  
            {  
                pos.y = hit.point.y;  
            }  
        }  
      
        // 更新角色的位置  
        transform.position = pos;  
        
    }
}
