using System.Threading.Tasks;
using Unity.Behavior;
using UnityEngine;
using UnityEngine.AI;

namespace XenseAR
{

    public class MascotManager : MonoBehaviour
    {
        [SerializeField]
        BehaviorGraphAgent mascotAgent;

        [SerializeField]
        NavMeshAgent mascotNavAgent;

        [SerializeField]
        GameObject mascotModel;

        [SerializeField]
        NavMeshAgent cameraAgent;

        [SerializeField]
        Camera camera;

        [SerializeField]
        GameObject NavigationWaypoint;

        [SerializeField]
        GameObject SpawnPoint;

        private static bool m_NavMeshReady = false;
        private static bool m_Scaned = false;
        private static bool m_MascotEnable = false;

        private const float CameraLeadDistance = 4f;
        private const float NavigationLeadDistance = 4f;

        public static float m_ModelScale = 0.6f;

        public static bool NavMeshReady
        {
            get => m_NavMeshReady;
            set
            {
                m_NavMeshReady = value;
                ResetAgent();
            }
        }

        public static bool Scaned
        {
            get => m_Scaned;
            set
            {
                m_Scaned = value;
                ResetAgent();
            }
        }

        public static bool MascotEnable
        {
            get => m_MascotEnable;
            set
            {
                m_MascotEnable = value;
                ResetAgent();
            }
        }

        public static float ModelScale
        {
            get => m_ModelScale;
            set
            {
                m_ModelScale = value;
                ResetAgent();
            }
        }

        // Start is called once before the first execution of Update after the MonoBehaviour is created
        void Start()
        {
            Scaned = false;
            NavMeshReady = false;
            MascotEnable = false;

            NavigationSystemManager.NavigationStatusChange += NavigationSystemManager_NavigationStatusChange;
            EventManager.Instance.AddListener(EVENT_TYPE.FinishloadNavMesh, OnFinishloadNavMesh);
        }

        private void Update()
        {
            if (cameraAgent.hasPath)
            {
                if (cameraAgent.path.corners.Length > 1)
                {
                    float distance = 0f;
                    Vector3 waypoint = cameraAgent.path.corners[0];

                    for (int i = 1; i < cameraAgent.path.corners.Length; i++)
                    {
                        if (distance + Vector3.Distance(waypoint, cameraAgent.path.corners[i]) < NavigationLeadDistance)
                        {
                            distance += Vector3.Distance(waypoint, cameraAgent.path.corners[i]);
                            waypoint = cameraAgent.path.corners[i];
                        }
                        else
                        {
                            waypoint = waypoint + (cameraAgent.path.corners[i] - waypoint).normalized * (NavigationLeadDistance - distance);
                            break;
                        }
                    }

                    try
                    {
                        NavigationWaypoint.GetComponent<NavMeshAgent>().Warp(waypoint);
                    } catch (System.Exception ex) { }
                }
            }
            SpawnPoint.transform.position = camera.transform.position + Vector3.Scale(camera.transform.forward, new Vector3(1f,0f,1f)).normalized * CameraLeadDistance;
        }

        public static async void ResetAgent()
        {
            MascotManager mascotManager = FindObjectOfType<MascotManager>(true);
            if (mascotManager == null) return;

            mascotManager.mascotModel.transform.localScale = Vector3.one * ModelScale;

            if (!m_NavMeshReady || !m_Scaned || !m_MascotEnable)
            {
                mascotManager.mascotAgent.End();
                mascotManager.mascotAgent.gameObject.SetActive(false);
                return;
            }

            mascotManager.mascotAgent.gameObject.SetActive(true);

            while (!mascotManager.mascotNavAgent.isOnNavMesh)
            {
                NavMeshHit navMeshHit = new NavMeshHit();
                if (NavMesh.SamplePosition(mascotManager.mascotNavAgent.transform.position, out navMeshHit, 100f, NavMesh.AllAreas))
                {
                    mascotManager.mascotNavAgent.Warp(navMeshHit.position);
                    break;
                }
                await Task.Yield();
            }

            mascotManager.mascotAgent.Start();
        }

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

        private void OnFinishloadNavMesh(EVENT_TYPE Event_Type, Component Sender, object Param)
        {
            NavMeshAgent mascotNavAgent = mascotAgent.GetComponentInChildren<NavMeshAgent>();
            if (!mascotNavAgent.isOnNavMesh)
            {
                if (cameraAgent.isOnNavMesh)
                {
                    mascotNavAgent.Warp(cameraAgent.transform.position);
                    mascotAgent.Restart();
                }
                else
                {
                    NavMeshHit hit = new NavMeshHit();
                    if (NavMesh.SamplePosition(cameraAgent.transform.position, out hit, 10f, NavMesh.AllAreas))
                    {
                        mascotNavAgent.Warp(hit.position);
                        mascotAgent.Restart();
                    }
                }
            }
        }

        private void NavigationSystemManager_NavigationStatusChange((NavigationEvent status, Vector3? destination) data)
        {
            switch (data.status)
            {
                case NavigationEvent.StartNavigate:
                    mascotAgent.SetVariableValue("flag_Navigating", true);
                    break;
                case NavigationEvent.DestinationChange:
                    break;
                case NavigationEvent.StopNavigate:
                    mascotAgent.SetVariableValue("flag_EndNavigate", true);
                    break;
                case NavigationEvent.PauseNavigate:
                    mascotAgent.SetVariableValue("flag_PauseNavigate", true);
                    break;
                case NavigationEvent.ResumeNavigate:
                    mascotAgent.SetVariableValue("flag_ContinueNavigate", true);
                    break;
                case NavigationEvent.DestinationArrived:
                    mascotAgent.SetVariableValue("flag_DestinationArrived", true);
                    break;
                default:
                    break;
            }
        }

        private static class MascotLine
        {
            private static readonly string[] _Welcome = new string[]
            {
                "Hey, you. You're finally awake. You were trying to cross the border, right? Walked right into that Imperial ambush, same as us, and that thief over there.",
                "Welcome to XenseAR"
            };

            public static readonly string[] _StartNavigate = new string[]
            {
                "Stanley walked on the arrow line.",
                "Navigating"
            };

            public static readonly string[] _DestinationChange = new string[]
            {
                "Changing course? Fine, but don’t blame me if you get lost.",
                "Re-routing"
            };
            
            public static readonly string[] _StopNavigate = new string[]
            {
                "Navigation disabled. Time to discover… or be discovered",
                "End Navigation."
            };

            public static readonly string[] _PauseNavigate = new string[]
            {
                "Go-on, i'll be right with you",
            };

            public static readonly string[] _ResumeNavigate = new string[]
            {
                "Alright, let's get going",
            };

            public static readonly string[] _DestinationArrived = new string[]
            {
                "Finally here! Hope you survived the trip.",
                "Destination arrived"
            };

            public static string Welcome { get => (string)_Welcome.GetValue(Random.Range(0, _Welcome.Length)); }

            public static string StartNavigate { get => (string)_StartNavigate.GetValue(Random.Range(0, _StartNavigate.Length)); }

            public static string DestinationChange { get => (string)_DestinationChange.GetValue(Random.Range(0, _DestinationChange.Length)); }

            public static string StopNavigate { get => (string)_StopNavigate.GetValue(Random.Range(0, _StopNavigate.Length)); }

            public static string PauseNavigate { get => (string)_PauseNavigate.GetValue(Random.Range(0, _PauseNavigate.Length)); }

            public static string ResumeNavigate { get => (string)_ResumeNavigate.GetValue(Random.Range(0, _ResumeNavigate.Length)); }

            public static string DestinationArrived { get => (string)_DestinationArrived.GetValue(Random.Range(0, _DestinationArrived.Length)); }
        }
    }
}
