using System;
using System.Collections.Generic;
using System.Linq;

using UnityEditor;

using UnityEngine;

using static EditorDefines.Priority.Navigation;

namespace XenseAR
{
    [CustomEditor(typeof(NavigationTargetEditor))]
    [CanEditMultipleObjects]
    public class NavigationTargetEditorGUI : Editor
    {
        bool isSelected = false;
        bool isEscape = false;
        bool isReturn = false;

        Vector2 locationScrollPosition = Vector2.zero;

        GameObject pickedObject;

        string lastFocus = "";

        #region Menu Item

        [MenuItem("ARWorld/Navigation/Create New Navigation Target", false, Create_Navigation_Target)]
        static void CreateNavigationTarget()
        {
            if (!Application.isEditor || !Application.isPlaying)
            {
                Debug.LogError("Navigation Target should only be create and edit within a playing editor");
                return;
            }

            NavigationTargetManager navigationTargetManager = FindObjectOfType<NavigationTargetManager>(true);

            if (navigationTargetManager == null)
            {
                Debug.LogError("No NavigationTargetManager found, make sure a NavigationTargetManager is present!");
                return;
            }

            if (navigationTargetManager.navTargetRoot.transform.childCount < 1)
            {
                Debug.LogError("No NavigationTargetRoot loaded, please load the root first");
                return;
            }

            GameObject parentObject = navigationTargetManager.navTargetRoot.transform.GetChild(0).gameObject;

            GameObject newTarget = new GameObject("New Navigation Target");
            newTarget.transform.SetParent(parentObject.transform);

            // Place navigation target in front of the scene view (if there is any)
            SceneView sceneView = SceneView.lastActiveSceneView;
            if (sceneView != null && sceneView.camera != null)
            {
                Camera cam = sceneView.camera;
                newTarget.transform.position = cam.transform.position + cam.transform.forward * 2f;
            }

            newTarget.AddComponent<NavigationTargetEditor>();

            Selection.activeGameObject = newTarget;
        }

        #endregion

        public void OnSceneGUI()
        {
            HandleUtility.AddDefaultControl(0);

            //Get the transform of the component with the selection base attribute
            Transform selectionBaseTransform = (target as NavigationTargetEditor).transform;

            if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
            {
                isSelected = true;
                //get picked object at mouse position
                pickedObject = HandleUtility.PickGameObject(Event.current.mousePosition, true);

                //If selected null or a non child of the component gameobject
                if (pickedObject != null && pickedObject.transform.IsChildOf(selectionBaseTransform))
                    pickedObject = selectionBaseTransform.gameObject;
            }

            if (Event.current.type == EventType.MouseMove || Event.current.type == EventType.MouseDrag || Event.current.button != 0)
            {
                isSelected = false;
                pickedObject = null;
            }

            if (isSelected && Event.current.type == EventType.MouseUp && Event.current.button == 0)
            {
                isSelected = false;
                Selection.activeObject = pickedObject;
            }
        }

        public override void OnInspectorGUI()
        {
            #region Detect key imput

            //Run key input detection before GUILayout Field

            if (Event.current.isKey == true && Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)
                isEscape = true;
            else if (Event.current.isKey == true && Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
                isReturn = true;
            else
            {
                isEscape = false;
                isReturn = false;
            }

            #endregion

            #region Main layout

            //--------------------------------------Target Name Display---------------------------------//

            DrawDefaultInspector();
            NavigationTargetEditor[] myScripts = Array.ConvertAll(targets, new Converter<UnityEngine.Object, NavigationTargetEditor>((obj) => { return obj as NavigationTargetEditor; }));

            GUILayout.BeginHorizontal();
            GUILayout.Label("Name", GUILayout.ExpandWidth(false), GUILayout.MinWidth(118));
            string name = "";
            if (myScripts.Select(myScript => myScript.gameObject.name).Distinct().Count() == 1)
                name = myScripts[0].gameObject.name;
            else name = " - ";

            string newName = GUILayout.TextField(name);
            newName?.Trim();
            if (newName != name)
            {
                foreach (var myScript in myScripts)
                {
                    myScript.gameObject.name = newName;
                    myScript.target.name = newName;
                    myScript.isEdited = true;
                }
            }
            GUILayout.EndHorizontal();

            //--------------------------------------Block Name Display (Uneditable)---------------------------------//

            GUILayout.BeginHorizontal();
            GUILayout.Label("Block", GUILayout.ExpandWidth(false), GUILayout.MinWidth(118));
            GUI.enabled = false;
            ARWorldBlockInfo ARWorldBlockInfo = null;
            if (myScripts.Select(myScript => myScript.blockRoot).Distinct().Count() == 1)
            {
                ARWorldBlockInfo = myScripts.Select(myScript => myScript.blockRoot).Distinct().First();
            }
            string blockRootID = "";
            if (ARWorldBlockInfo != null) blockRootID = ARWorldBlockInfo.GetInfo().ID;
            GUILayout.TextField(blockRootID);
            GUI.enabled = true;
            GUILayout.EndHorizontal();

            //--------------------------------------Location Name/ID Selection---------------------------------//

            GUILayout.BeginHorizontal();
            GUILayout.Label("Location *", GUILayout.ExpandWidth(false), GUILayout.MinWidth(118));
            if (!EditorApplication.isPlaying) GUI.enabled = false;

            string locationName = "";
            string locationCategoryName = "";
            string locationDetail = "";
            if (myScripts.Select(myScript => myScript.locationInfo.id).Distinct().Count() == 1)
            {
                locationName = myScripts[0].locationInfo.name;
                locationCategoryName = myScripts[0].locationInfo.category.name;
                locationDetail = myScripts[0].locationInfo.location;
            }
            else
            {
                locationName = " - ";
            }

            GUI.SetNextControlName("newLocationName");
            string newLocationInput = $"{locationName}" +
                (string.IsNullOrEmpty(locationCategoryName) ? "" : $" | {locationCategoryName}") +
                (string.IsNullOrEmpty(locationDetail) ? "" : $" | {locationDetail}");
            newLocationInput = EditorGUILayout.TextField(newLocationInput);

            GUILayout.EndHorizontal();
            NavigationTargetManager navigationTargetManager = Container.Resolve<NavigationTargetManager>();
            if (EditorApplication.isPlaying && navigationTargetManager.locationLoadSuccess)
            {
                LocationInfo currentLocation = navigationTargetManager.GetAvailableLocationInfos().Where(location => location.id == myScripts[0].locationInfo.id).ToList().FirstOrDefault();
                foreach (var myScript in myScripts)
                {
                    myScript.locationInfo.name = newLocationInput.Split("|")[0].Trim();
                }
                if (currentLocation == null || newLocationInput.Split("|")[0].Trim() != currentLocation.name)
                {
                    List<LocationInfo> availableLocations = navigationTargetManager.GetAvailableLocationInfos().Where(location => location.name.ToLower().Contains(newLocationInput.Split("|")[0].Trim().ToLower())).ToList();
                    if (availableLocations.Count > 10)
                        locationScrollPosition = GUILayout.BeginScrollView(locationScrollPosition, GUILayout.Height(210f));
                    else
                        locationScrollPosition = GUILayout.BeginScrollView(locationScrollPosition);
                    bool selectByButton = false;
                    foreach (var location in availableLocations)
                    {
                        string buttonText = $"{location.name}" +
                            (string.IsNullOrEmpty(location.category.name) ? "" : $" | {location.category.name}") +
                            (string.IsNullOrEmpty(location.location) ? "" : $" | {location.location}");
                        if (GUILayout.Button(buttonText))
                        {
                            selectByButton = true;
                            newLocationInput = $"{location.name}" +
                                (string.IsNullOrEmpty(location.category.name) ? "" : $" | {location.category.name}") +
                                (string.IsNullOrEmpty(location.location) ? "" : $" | {location.location}");
                            foreach (var myScript in myScripts)
                            {
                                myScript.target.locationID = location.id;
                                myScript.isEdited = true;
                                myScript.UpdateLocationInfo();
                            }
                        }
                    }
                    GUILayout.EndScrollView();

                    if (!selectByButton)
                    {
                        bool isFocused = GUI.GetNameOfFocusedControl() == "newLocationName";
                        if (lastFocus == "newLocationName" && !isFocused)
                        {
                            foreach (var myScript in myScripts)
                            {
                                myScript.UpdateLocationInfo();
                            }
                        }
                        if (lastFocus == "newLocationName" && isFocused && isReturn && availableLocations != null && availableLocations.Count > 0)
                        {
                            LocationInfo selected = availableLocations[0];
                            newLocationInput  = $"{selected.name}" +
                            (string.IsNullOrEmpty(selected.category.name) ? "" : $" | {selected.category.name}") +
                            (string.IsNullOrEmpty(selected.location) ? "" : $" | {selected.location}");
                            foreach (var myScript in myScripts)
                            {
                                myScript.target.locationID = selected.id;
                                myScript.isEdited = true;
                                myScript.UpdateLocationInfo();
                            }
                        }
                    }
                }
            }
            GUI.enabled = true;

            #endregion

            #region Control button

            GUILayout.Space(10);
            GUILayout.Box(Utility.CreateTexture2D(Color.white), new GUIStyle()
            {
                stretchWidth = true,
                fixedHeight = 1,
                normal = new GUIStyleState() { background = Utility.CreateTexture2D(Color.white), }
            });
            GUILayout.Space(10);

            if (!EditorApplication.isPlaying)
            {
                GUI.enabled = false;
                GUILayout.Button("Start playing to edit");
                GUI.enabled = true;
                return;
            }

            if (myScripts.Where(myScript => myScript.isUpdating == true).Count() > 0)
            {
                GUI.enabled = false;
                GUILayout.Button("Updating");
                GUI.enabled = true;
                return;
            }

            if (myScripts.Where(myScript => myScript.isNew == true).Count() == myScripts.Count())
            {
                if (GUILayout.Button("Create"))
                {
                    foreach (var script in myScripts) script.Save();
                }
            }
            else
            {
                if (!myScripts.Where(myScript => myScript.isDeleted == true).Any())
                {
                    if (GUILayout.Button("Save"))
                    {
                        foreach (var script in myScripts) script.Save();
                    }
                }
                else
                {
                    GUI.enabled = false;
                    GUILayout.Button("Save");
                    GUI.enabled = true;
                }
            }

            if (!myScripts.Where(myScript => myScript.isNew == true || myScript.isDeleted == true).Any())
            {
                if (GUILayout.Button("Reload"))
                {
                    foreach (var script in myScripts) script.Reload();
                }
            }
            else
            {
                GUI.enabled = false;
                GUILayout.Button("Reload");
                GUI.enabled = true;
            }

            if (GUILayout.Button("Verify"))
            {
                foreach (var script in myScripts) script.Verify();
            }

            if (myScripts.Length == 1)
            {
                if (!myScripts[0].isTesting_Navigate)
                {
                    if (GUILayout.Button("Start navigation testing"))
                    {
                        myScripts[0].StartNavigationTesting();
                    }
                }
                else
                {
                    if (GUILayout.Button("End navigation tesing"))
                    {
                        myScripts[0].EndNavigationTesting();
                    }
                }
            }

            if (myScripts.Where(myScript => myScript.isDeleted == true).Count() != myScripts.Count())
            {
                if (GUILayout.Button("Delete"))
                {
                    foreach (var script in myScripts) script.Delete();
                }
            }

            if (myScripts.Where(myScript => myScript.isDeleted == true).Count() == myScripts.Count())
            {
                if (GUILayout.Button("Restore"))
                {
                    foreach (var script in myScripts)
                    {
                        script.isNew = true;
                        script.Save();
                    }
                }
            }
            #endregion

            lastFocus = GUI.GetNameOfFocusedControl();
        }
    }
}
