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

using UnityEngine;
namespace XenseAR
{
    public class NavigationMeshManager : MonoBehaviour
    {
        [SerializeField] AppSettingObject appSetting;
        [SerializeField] DataScriptableObject sessionDataObject;
        [SerializeField] GameObject navMeshRoot;

        DataLoader loader;

        GameObject parentRoot;
        private bool hasLoad = false;
        private bool onLoading = false;
        private string currentBlockID;

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

        /// <summary>
        /// For faster navmesh load, since navmesh don't interfer with other component
        /// We load from the start
        /// </summary>
        private void Start()
        {
            if (loader == null) loader = new DataLoader();

            StartLoadAsync();
        }

        public void LoadBlock(string blockID)
        {
            if (!string.IsNullOrEmpty(currentBlockID))
            {
                if (!currentBlockID.Contains(blockID))
                {
                    OnBlockIDChange(currentBlockID);
                }
            }
            currentBlockID = blockID;
            StartLoadAsync();
        }

        public async Task StartLoadAsync()
        {
            if (hasLoad) return;
            if (onLoading) return;

            onLoading = true;
            await LoadBlockData();
            onLoading = false;
            hasLoad = true;
        }

        public async Task<bool> LoadBlockData()
        {
            if (loader == null) loader = new DataLoader();
            if (sessionDataObject == null)
            {
                hasLoad = false;
                return false;
            }

            var blockControllers = FindObjectsOfType<ARWorldBlockInfo>(true);
            ARWorldBlockInfo blockController = null;
            if (blockControllers == null || blockControllers.Count() == 0)
            {
                if (!string.IsNullOrEmpty(appSetting.LocationSetting.blockId))
                {
                    currentBlockID = appSetting.LocationSetting.blockId;
                    blockController = new ARWorldBlockInfo();
                    blockController.UpdateInfo(new BlockInfo()
                    {
                        ID = appSetting.LocationSetting.blockId,
                        Name = appSetting.LocationSetting.name
                    });
                }
                else
                {
                    hasLoad = false;
                    return false;
                }
            }
            else
            {
                blockController = blockControllers[0];
            }

            if (loader.isEdit)
            {
                loader.SetNavigationMeshRoot(navMeshRoot, blockController, sessionDataObject);
                return await loader.LoadNavigationMeshEdu(blockController.GetInfo(), LoadNavMesh, onFinishLoadNavMesh);
            }
            else
            {
                loader.SetNavigationMeshRoot(navMeshRoot, blockController, sessionDataObject);
                return await loader.LoadNavigationMeshEdu(blockController.GetInfo(), LoadNavMesh, onFinishLoadNavMesh);
            }
        }

        private async void LoadNavMesh(NavigationMesh navigationMesh, GameObject parentRoot)
        {
            this.parentRoot = parentRoot;
            AssetBundleLoader loader = new AssetBundleLoader(this, navigationMesh.url, "");
            bool loadSuccess = false;
            var destroyToken = destroyCancellationToken;
            int retryCount = 3;
            while (!loadSuccess && !destroyToken.IsCancellationRequested && retryCount > 0)
            {
                loadSuccess = await loader.LoadAsync(LoadNavMeshBundle, true);
                retryCount--;
            }
        }

        private void LoadNavMeshBundle(GameObject result)
        {
            foreach (MeshFilter meshFilter in result.GetComponentsInChildren<MeshFilter>(true))
            {
                if (meshFilter.gameObject.GetComponent<MeshCollider>() == null)
                {
                    MeshCollider meshCollider = meshFilter.gameObject.AddComponent<MeshCollider>();
                    meshCollider.sharedMesh = meshFilter.sharedMesh;
                }
            }

            result.transform.SetParent(parentRoot.transform);
            result.transform.localPosition = Vector3.zero;
            result.transform.localRotation = Quaternion.identity;
            result.transform.localScale = Vector3.one;

            MascotManager.NavMeshReady = true;

            EventManager.Instance?.PostNotification(EVENT_TYPE.FinishloadNavMesh, this);
        }

        private void onFinishLoadNavMesh()
        {
        }

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

            int oldTargetCount = navMeshRoot.transform.childCount;

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

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

            navTarget.Clear();
        }

        private void OnBlockIDChange(string blockToCleanId)
        {
            hasLoad = false;
            DeleteOldNavigationTarget();
        }

        public GameObject GetNavMeshRoot()
        {
            return navMeshRoot;
        }
    }
}
