using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
namespace XenseAR
{

    public class NavigationLineManager : MonoBehaviour
    {
        [SerializeField] Camera ARCamera;

        [Header("Navigation 3D UI Component")]
        [SerializeField] public LineRenderer NavigationLine;
        [SerializeField] GameObject destinationPinPrefab;
        [SerializeField] GameObject Compass;

        [Header("Line Setting")]
        [SerializeField] bool gradient = true;
        [Tooltip("The distance from camera position to where the render end, unit is meter")]
        [SerializeField] float gradientLineRenderDistance = 10f;

        [SerializeField] bool animatedLine = true;
        [Tooltip("The speed at which line renderer texture move, unit is meter/second")]
        [SerializeField] float animatedLineSpeed = 1f; //Unit is meter/second

        GameObject destinationPin;

        NavMeshPath path;
        NavMeshPath drawPath;

        NavigationSystemManager navigationSystemManager;

        float foundlinedistance = 15f;
        float notFoundlinedistance = 6f;
        float upoffset = 0.05f;

        void Awake()
        {
            Container.Register(this);
        }

        void Start()
        {
            navigationSystemManager = Container.Resolve<NavigationSystemManager>();
            NavigationSystemManager.NavigationStatusChange += OnNavigationStatusChange;

            if (!SceneManager.GetActiveScene().name.Trim().ToLower().Contains("editor"))
                destinationPin = Instantiate(destinationPinPrefab, transform);

            if (ARCamera == null)
            {
                ARCamera = Camera.main;
            }
        }

        private void OnDestroy()
        {
            NavigationSystemManager.NavigationStatusChange -= OnNavigationStatusChange;
        }

        void Update()
        {
            if (animatedLine)
            {
                AnimatingLine();
            }
            UpdateCompass();
        }

        private void OnNavigationStatusChange((NavigationEvent state, Vector3? destination) data)
        {
            switch (data.state)
            {
                case NavigationEvent.StartNavigate:
                    if (!destinationPin) return;
                    destinationPin.transform.position = data.destination.Value;
                    destinationPin.SetActive(true);
                    //Compass.SetActive(true);
                    break;
                case NavigationEvent.DestinationChange:
                    if (!destinationPin) return;
                    destinationPin.transform.position = data.destination.Value;
                    break;
                case NavigationEvent.StopNavigate:
                    if (!destinationPin) return;
                    destinationPin.SetActive(false);
                    //Compass.SetActive(false);
                    break;
                case NavigationEvent.PauseNavigate:
                    //Compass.SetActive(false);
                    break;
                case NavigationEvent.ResumeNavigate:
                    //Compass.SetActive(true);
                    break;
                case NavigationEvent.DestinationArrived:
                    break;
                default:
                    break;
            }
        }

        public void UpdateNavigationLineVisibility(bool hasFoundTargetArea, Vector3? currentDestination, NavMeshPath path)
        {
            if (hasFoundTargetArea && currentDestination.HasValue)
                NavigationLine.enabled = true;
            else NavigationLine.enabled = false;

            this.path = path;
        }

        public void DrawPath()
        {
            if (path == null)
                return;

            drawPath = path;

            Vector3[] drawCorners = drawPath.corners;

            for (int i = 0; i < drawCorners.Length; i++)
            {
                drawCorners[i] += Vector3.up * upoffset;
            }

            //gradient draw
            if (gradient && drawPath.corners.Length > 1)
            {
                float totalDistance = 0f;
                for (int i = 1; i < drawCorners.Length; i++)
                {
                    totalDistance = totalDistance + Vector3.Distance(drawCorners[i], drawCorners[i - 1]);
                }

                if (totalDistance > gradientLineRenderDistance)
                {
                    float time = (totalDistance - gradientLineRenderDistance) / totalDistance;
                    Gradient drawGradient = new Gradient();
                    drawGradient.SetKeys(
                        new GradientColorKey[] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) },
                        new GradientAlphaKey[] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0f, time), new GradientAlphaKey(1f, 1f) }
                    );
                    NavigationLine.colorGradient = drawGradient;

                    float count = 0f;
                    for (int i = 1; i < drawCorners.Length; i++)
                    {
                        float segmentLength = Vector3.Distance(drawCorners[i], drawCorners[i - 1]);
                        if (count + segmentLength > gradientLineRenderDistance)
                        {
                            Vector3 linePoint = drawCorners[i - 1] + (drawCorners[i] - drawCorners[i - 1]).normalized * (gradientLineRenderDistance - count);
                            List<Vector3> temp = drawCorners.ToList();
                            temp.Insert(i, linePoint);
                            drawCorners = temp.ToArray();
                            break;
                        }
                        count = count + segmentLength;
                    }
                }
                else
                {
                    float time = (gradientLineRenderDistance - totalDistance) / gradientLineRenderDistance;
                    Gradient drawGradient = new Gradient();
                    drawGradient.SetKeys(
                        new GradientColorKey[] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) },
                        new GradientAlphaKey[] { new GradientAlphaKey(time, 0f), new GradientAlphaKey(1f, 1f) }
                    );
                    NavigationLine.colorGradient = drawGradient;
                }

                if (!SceneManager.GetActiveScene().name.Trim().ToLower().Contains("editor"))
                {
                    if (totalDistance > 3.5f)
                        destinationPin.SetActive(true);
                    else
                        destinationPin.SetActive(false);
                }
            }

            NavigationLine.positionCount = drawCorners.Length;
            NavigationLine.SetPositions(drawCorners.Reverse().ToArray());
        }

        private void UpdateCompass()
        {
            return;
            if (drawPath == null || drawPath.corners.Length < 2) return;

            Vector3 angle = Utility.CaculateAngle(ARCamera.transform.forward, drawPath.corners[1] - drawPath.corners[0]);
            Compass.transform.localEulerAngles = new Vector3(0f, 180f + angle.y, 0f);
        }

        void AnimatingLine()
        {
            if (NavigationLine.enabled)
            {
                NavigationLine.material.mainTextureOffset += new Vector2(animatedLineSpeed * Time.deltaTime, 0f);
                if (NavigationLine.material.mainTextureOffset.x > 100f)
                    NavigationLine.material.mainTextureOffset -= new Vector2(100f, 0f);
            }
        }
    }
}
