using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using UnityEngine;
using UnityEngine.Networking;
using XenseAR;
namespace CBLP.MegaStudio
{
    public class SimplifiedDataManager : MonoBehaviour
    {
        string rootName = "XenseARBlocks";
        public bool importing = false;
        string hostURL = "https://xensear.vn/api/v1/";

        public CancellationTokenSource cts;
        public XenseARBlockRoot RootBlock;
        public List<BlockItem> Blocks = new List<BlockItem>();

        public bool hideChild = false;
        public string importUrl = "";
        public string message = "";

        public string blockId = "";
        public string worldSpaceId = "";
        public string groupId = "";

        ARWorldBlockInfo currentBlock;


        public List<BlockItem> FullList = new List<BlockItem>();

        [Serializable]
        public class BlockItem
        {
            public string blockId;
            public string title;
            public string url;

            public BlockItem(string blockId, string title, string url)
            {
                this.blockId = blockId;
                this.title = title;
                this.url = url;
            }
        }

        [Serializable]
        private class AvailableBlocksResponse
        {
            public string status;
            public string message;
            public List<BlockItem> data;
        }

        public void LoadBlockList()
        {
            //Load blocks
            StartCoroutine(GetAvailableBlock());
        }

        IEnumerator GetAvailableBlock()
        {
            using (UnityWebRequest www = UnityWebRequest.Post(hostURL, "{ \"type\": \"GetAvailableBlock\"}", "application/json"))
            {
                yield return www.SendWebRequest();

                if (www.result != UnityWebRequest.Result.Success)
                {
                    Debug.LogError(www.error);
                }
                else
                {
                    OnFinishSave(www.downloadHandler.text);
                }
            }
        }

        public GameObject GetGameObject()
        {
            return this.gameObject;
        }

        public void CreateBlockRoot()
        {
            RootBlock = new GameObject(rootName).AddComponent<XenseARBlockRoot>();
        }

        private void OnFinishSave(string resText)
        {
            Debug.Log("Load done");
            FullList = JsonUtility.FromJson<AvailableBlocksResponse>(resText).data;
            Blocks = FullList;
            string blockUrl = "";
            foreach(BlockItem blockItem in Blocks)
            {
                if(blockId.Equals(blockItem.blockId))
                {
                    blockUrl = blockItem.url;
                    break;
                }
            }
            Debug.Log("Details: " + blockId + " - " + blockUrl);
            if(string.IsNullOrEmpty(blockUrl))
            {
                Debug.Log("Wrong Details Provided!");
            }
            if(RootBlock == null)
            {
                Debug.Log("Please select Root Block!");
                return;
            }
            ImportMesh(blockId, blockUrl);
        }

        public async void ImportMesh(string id, string url)
        {
            if (importing) return;
            cts = new CancellationTokenSource();
            ClearChild(RootBlock.gameObject);

            foreach (var block in Blocks)
            {
                if (!id.Equals(block.blockId)) continue;
                ARWorldBlockInfo newChild = new GameObject("Block_" + block.title).AddComponent<ARWorldBlockInfo>();
                newChild.transform.parent = RootBlock.transform;
                BlockInfo newBlockInfo = new BlockInfo();
                newBlockInfo.ID = block.blockId;
                newBlockInfo.Name = block.title;
                newChild.UpdateInfo(newBlockInfo);

                if (string.IsNullOrEmpty(url))
                {
                    Debug.Log("Empty Mesh Data detected!!! Contact your provider!");
                }
                else
                {
                    hideChild = false;
                    AssetBundleLoader loader = new AssetBundleLoader(this, url, "");
                    var loadingTask = loader.LoadAsync(null, true, null, cts.Token);
                    importing = true;
                    importUrl = url;
                    Debug.Log("Import in progress");
                    message = "Downloading...";
                    await loadingTask;
                    importing = false;
                    importUrl = string.Empty;
                    message = "";
                    hideChild = true;
                    Debug.Log("Import Mesh Done");
                    LoadContent(newChild);
                }
            }
        }

        private bool isWorldSelectorCreated = false;

        public async void LoadContent(ARWorldBlockInfo newChild)
        {
            await Container.Resolve<AnchoringManager>()?.LoadBlockData();
            isWorldSelectorCreated = false;
            currentBlock = newChild;
            InvokeRepeating("CheckWorldSelectorCreated", 0, 1);
            LoadWorldData(newChild);
        }

        public void CheckWorldSelectorCreated()
        {
            if(currentBlock == null)
            {
                CancelInvoke("CheckWorldSelectorCreated");
            }
            WorldSelector worldSelector = currentBlock.GetComponent<WorldSelector>();
            if (worldSelector)
            {
                isWorldSelectorCreated = true;
                worldSelector.hideFlags = HideFlags.HideInInspector;
            }
            Debug.Log("Done load: " + isWorldSelectorCreated);
        }

        async Task<bool> LoadWorldData(ARWorldBlockInfo newChild)
        {
            while (!isWorldSelectorCreated) {
                await Task.Yield();
            }
            WorldSelector worldSelector = newChild.GetComponent<WorldSelector>();
            if (worldSelector)
            {
                worldSelector.worldId = worldSpaceId;
                worldSelector.LoadGroupData(groupId);
                CancelInvoke("CheckWorldSelectorCreated");
            }
            return true;
        }

        public void StopImportMesh()
        {
            cts?.Cancel();
            importing = false;
            importUrl = string.Empty;
            message = "";
            hideChild = false;
        }

        public void ClearChild(GameObject parent)
        {
            List<GameObject> childBlocks = new List<GameObject>();
            int childCount = parent.transform.childCount;
            for (int i = 0; i < childCount; i++)
            {
                childBlocks.Add(parent.transform.GetChild(i).gameObject);
            }

            foreach (GameObject childBlock in childBlocks)
            {
                DestroyImmediate(childBlock);
            }
        }
    }
}
