using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;

using UnityEngine;
namespace XenseAR
{
    public class NavigationTargetManager : MonoBehaviour
    {
        [SerializeField] DataScriptableObject sessionDataObject;
        [SerializeField] public GameObject navTargetRoot;

        DataLoader loader;

        bool targetLoading = false;
        bool targetLoadSuccess = false;

        bool locationLoading = false;
        public bool locationLoadSuccess = false;

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

        private void Start()
        {
            if (loader == null) loader = new DataLoader();
        }

        private void OnDestroy()
        {
            sessionDataObject.SessionData.navigation.locations.Clear();
            sessionDataObject.SessionData.navigation.targets.Clear();
        }

        public void LoadBlockData()
        {
            if (sessionDataObject == null)
            {
                Debug.LogError("SessionData is not assigned!");
                return;
            }

            DeleteOldNavigationTarget();

            var blockControllers = FindObjectsOfType<ARWorldBlockInfo>();
            if (blockControllers == null || blockControllers.Count() == 0)
            {
                Debug.Log("Cannot find any enabled ARWorldBlockInfo in the scene!");
                return;
            }

            if (blockControllers.Count() != 1)
            {
                Debug.LogError("Please only enable ARWorldBlockInfo which you wish to edit!");
                return;
            }

            if (targetLoading || locationLoading)
            {
                Debug.LogError("Navigation Target is being load, please wait!");
                return;
            }

            targetLoading = true;
            locationLoading = true;
            targetLoadSuccess = false;
            locationLoadSuccess = false;

            loader.SetNavigationTargetRoot(navTargetRoot, blockControllers[0], sessionDataObject);
            loader.LoadLocationInfos(OnFinishLoadLocationInfo);
            loader.LoadNavigationTargetEdu(OnFinishLoadNavigationTarget);
        }

        public void OnFinishLoadNavigationTarget(bool result)
        {
            targetLoading = false;
            targetLoadSuccess = result;
            FinishLoad();
        }

        public void OnFinishLoadLocationInfo(bool result)
        {
            locationLoading = false;
            locationLoadSuccess = result;
            FinishLoad();
        }

        private async void FinishLoad()
        {
            if (!targetLoading && !locationLoading)
            {
                if (targetLoadSuccess && locationLoadSuccess)
                {
                    await UniTask.NextFrame();
                    var navigationTargetEditors = loader.InitializeNavigationTarget();
                    foreach (var targetEditor in navigationTargetEditors)
                        targetEditor.UpdateLocationInfo();
                }
                else
                {
                    Debug.LogError("Fail to load Navigation target Data\n" +
                        $"Target load {targetLoadSuccess}\n" +
                        $"Location load {locationLoadSuccess}");
                    DeleteOldNavigationTarget();
                }
            }
        }

        public void DeleteOldNavigationTarget()
        {
            if (navTargetRoot == null) return;

            int oldTargetCount = navTargetRoot.transform.childCount;

            List<GameObject> navTargets = new List<GameObject>();
            for (int i = 0; i < oldTargetCount; i++)
            {
                navTargets.Add(navTargetRoot.transform.GetChild(i).gameObject);
            }

            foreach (GameObject target in navTargets)
            {
                Destroy(target);
            }

            navTargets.Clear();
        }

        public List<LocationInfo> GetAvailableLocationInfos()
        {
            return sessionDataObject.SessionData.navigation.locations;
        }

        public void SaveAllNavigationTarget()
        {
            NavigationTargetEditor[] navigationEditors = GetComponentsInChildren<NavigationTargetEditor>(true);
            foreach (NavigationTargetEditor navigationEditor in navigationEditors)
            {
                navigationEditor.Save();
            }
        }
    }
}
