using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;

namespace XenseAR.Localization
{
    public class XenseARLocalizationDataFetcher : MonoBehaviour
    {
        [SerializeField] DictionaryOverviewObject dictionaryOverviewData;

        [SerializeField] DictionaryFallbackObject fallbackData;

        [SerializeField] string dictionaryOverviewUrl;

        string dictionaryOverviewFileName;

        public bool forceUpdateDictionary = false;

        string dictionaryDirectory;

        string dictionaryOverviewLocalPath;

        private void Awake()
        {
            XenseARDictionary.Instance.dictionaryOverviewData = dictionaryOverviewData;
        }

        private void Start()
        {
            dictionaryDirectory = Path.Combine(Application.persistentDataPath, "Dictionary");
            dictionaryOverviewFileName = Path.GetFileName(dictionaryOverviewUrl);
            if (!Directory.Exists(dictionaryDirectory))
            {
                Directory.CreateDirectory(dictionaryDirectory);
            }
            Debug.Log("Localization Cache in: " + dictionaryDirectory);

            StartCoroutine(GetRequest(dictionaryOverviewUrl, OnFetchDictionaryOverviewDataDone, dictionaryOverviewFileName));
            LoadFallbackData();
        }

        // Local Data Access
        private void LoadFallbackData()
        {
            dictionaryOverviewData.dictionaryOverview.fallbackText.Clear();
            foreach (LocalizationData item in fallbackData.fallbackData)
            {
                dictionaryOverviewData.dictionaryOverview.fallbackText.Add(item.key, item.text);
            }

            if(Application.isEditor)
            {
                string jsonData = JsonUtility.ToJson(fallbackData);
                FileUtility.WriteFileData(dictionaryDirectory, "/text/fallback.txt", jsonData);
            }
        }

        private void PopulateDictionary()
        {
            foreach (XenseARLanguage item in dictionaryOverviewData.dictionaryOverview.languages)
            {
                if(dictionaryOverviewData.dictionaryOverview.selectedLaguage.Equals(item.key))
                {
                    //read data from file
                    // load to dictionary
                    string fileData = FileUtility.ReadFileData(dictionaryDirectory, item.dictionaryPath);
                    LocalizationDataList datas = JsonUtility.FromJson<LocalizationDataList>(fileData);
                    dictionaryOverviewData.dictionaryOverview.currentLanguageText.Clear();
                    foreach (LocalizationData data in datas.data) {
                        dictionaryOverviewData.dictionaryOverview.currentLanguageText.Add(data.key, data.text);
                    }
                    XenseARDictionary.Instance.PerformUpdateText();
                    break;
                }
            }
        }

        //

        // Remote Data Access
        private void StartLoadDictionary()
        {
            foreach (XenseARLanguage item in dictionaryOverviewData.dictionaryOverview.languages) {
                StartCoroutine(GetRequest(FileUtility.GetLink(dictionaryOverviewUrl, item.dictionaryPath), OnFetchDictionaryDataDone, item.dictionaryPath));
            }
        }

        void OnFetchDictionaryDataDone(string savePath, string result)
        {
            if (result != null)
            {
                //Debug.Log($"Received: {result}");

                if(File.Exists(Path.Combine(dictionaryDirectory, savePath)))
                {
                    File.Delete(Path.Combine(dictionaryDirectory, savePath));
                }
                FileUtility.WriteFileData(dictionaryDirectory, savePath, result);
                if(Path.GetFileName(savePath).Equals(dictionaryOverviewData.dictionaryOverview.selectedLaguage + ".txt"))
                {
                    PopulateDictionary();
                }
            }
            else
            {
                Debug.LogError("Failed to retrieve data.");
            }
        }

        void OnFetchDictionaryOverviewDataDone(string savePath, string result)
        {
            if (result != null)
            {
                //Debug.Log($"Received: {result}");
                bool needLoadDictionary = false;

                dictionaryOverviewData.dictionaryOverview.version = JsonUtility.FromJson<DictionaryOverview>(result).version;
                dictionaryOverviewData.dictionaryOverview.languages = JsonUtility.FromJson<DictionaryOverview>(result).languages;

                if(File.Exists(Path.Combine(dictionaryDirectory, dictionaryOverviewFileName))) {
                    DictionaryOverview currentCache = 
                        JsonUtility.FromJson<DictionaryOverview> 
                        (FileUtility.ReadFileData(dictionaryDirectory, savePath));

                    if(String.Compare(dictionaryOverviewData.dictionaryOverview.version, currentCache.version) > 0 || forceUpdateDictionary)
                    {
                        needLoadDictionary = true;

                        File.Delete(Path.Combine(dictionaryDirectory, savePath));
                        FileUtility.WriteFileData(dictionaryDirectory, savePath, result);
                    }
                }
                else
                {
                    needLoadDictionary = true;
                    FileUtility.WriteFileData(dictionaryDirectory, savePath, result);
                }

                if(needLoadDictionary)
                {
                    StartLoadDictionary();
                } else
                {
                    PopulateDictionary();
                }
            }
            else
            {
                Debug.LogError("Failed to retrieve data.");
            }
        }
        //

        IEnumerator GetRequest(string uri, System.Action<string, string> callback, string savePath)
        {
            using (UnityWebRequest webRequest = UnityWebRequest.Get(uri))
            {
                // Send the request and wait for a response
                yield return webRequest.SendWebRequest();

                // Check for errors
                if (webRequest.result == UnityWebRequest.Result.ConnectionError ||
                    webRequest.result == UnityWebRequest.Result.DataProcessingError)
                {
                    Debug.LogError($"Error: {webRequest.error}");
                }
                else if (webRequest.result == UnityWebRequest.Result.ProtocolError)
                {
                    Debug.LogError($"HTTP Error: {webRequest.error}");
                }
                else
                {
                    // Successfully received the response
                    callback(savePath, webRequest.downloadHandler.text);
                }
            }
        }

    }
}

    
