using System;
using System.Collections.Generic;
using System.IO;
using JetBrains.Annotations;
using SGModule.Common;
using SGModule.Common.Base;
using SGModule.Common.Extensions;
using SGModule.Common.Helper;
using UnityEngine;
using UnityEngine.Events;

namespace SGModule.ConfigLoader
{
    public enum ConfigLoaderState
    {
        None,
        Failed,
        JsonEmptyError,
        Successful
    }

    public class ConfigLoader : SingletonMonoBehaviour<ConfigLoader>
    {
        private const int MaxErrorCount = 6;
        private const string ConfigFileNameKey = "ConfigFileName";
        private readonly Dictionary<Type, object> _configData = new();
        private readonly Dictionary<string, ConfigModel> _userDefinedConfig = new();

        private string _cdnConfigFileName;
        private string _cdnUrl;

        private string _configJson;

        private int _initConfigErrorCount;

        private bool _isConfigLoaded;
        private Dictionary<string, object> _jsonDictionary = new();

        // 暴露只读接口
        public IReadOnlyDictionary<string, object> JsonDictionary => _jsonDictionary;

        /// <summary>
        ///     初始化配置模块方法
        /// </summary>
        /// <param name="cdnConfigFileName">登录获得的配置文件名</param>
        /// <param name="cdnUrl">下载配置的地址</param>
        /// <param name="configs">需要初始化解析的配置</param>
        /// <param name="configLoadCallback">配置加载回调</param>
        /// <param name="parseErrorHandler">配置解析错误回调</param>
        public void Init(string cdnConfigFileName, string cdnUrl, List<ConfigModel> configs,
            UnityAction<ConfigLoaderState> configLoadCallback = null,
            UnityAction<string, string> parseErrorHandler = null)
        {
            _cdnConfigFileName = cdnConfigFileName;
            _cdnUrl = cdnUrl;

            IsInitComplete = true;

            CheckConfigFile(state =>
            {
                if (state == ConfigLoaderState.Successful)
                {
                    InitConfigList(configs, parseErrorHandler);
                }

                configLoadCallback?.Invoke(state);
            });
        }

        /// <summary>
        ///     批量解析配置文件
        /// </summary>
        /// <param name="configs"></param>
        /// <param name="errorCallback"></param>
        private void InitConfigList(List<ConfigModel> configs, UnityAction<string, string> errorCallback = null)
        {
            foreach (var config in configs)
            {
                Pares(config, errorCallback);
            }
        }

        /// <summary>
        ///     检查并加载配置文件
        /// </summary>
        /// <param name="callback"></param>
        private void CheckConfigFile(UnityAction<ConfigLoaderState> callback)
        {
            if (!IsInitComplete)
            {
                Log.ConfigLoader.Warning("配置加载模块模块未初始化");

                return;
            }

            if (_initConfigErrorCount > MaxErrorCount)
            {
                callback?.Invoke(ConfigLoaderState.Failed);
                return;
            }

            if (IsFirstLaunch())
            {
                FirstLaunchCopyConfig(callback); // 进行首次启动的操作
                return;
            }

            bool needDownloadConfigFile = false;
            if ((!string.IsNullOrEmpty(_cdnConfigFileName)) && PlayerPrefs.GetString(ConfigFileNameKey, "") != _cdnConfigFileName) needDownloadConfigFile = true;
            //需要下载配置的话等待下载更新
            if (needDownloadConfigFile)
            {
                DownloadConfig(callback);
                return;
            }

            ReadLocalConfig(callback);
        }

        /// <summary>
        ///     判断是首次打开游戏
        /// </summary>
        /// <returns></returns>
        private bool IsFirstLaunch()
        {
            return !PlayerPrefs.HasKey("FirstLaunch");
        }

        /// <summary>
        ///     设置首次启动游戏
        /// </summary>
        private void SetFirstLaunch()
        {
            PlayerPrefs.SetInt("FirstLaunch", 1);
        }

        /// <summary>
        ///     首次启动游戏拷贝配置文件到PersistentData目录下
        /// </summary>
        private void FirstLaunchCopyConfig(UnityAction<ConfigLoaderState> callback)
        {
            SetFirstLaunch();
            FileNetworkManager.Instance.CopyStreamingAssetsToPersistentDataPath(result =>
            {
                var isSuccess = false;
                if (result)
                {
                    var names =
                        FileNetworkManager.Instance.GetFileNamesFromPersistentDataPath(FileNetworkManager.FolderName);
                    if (names.Length > 0)
                    {
                        PlayerPrefs.SetString(ConfigFileNameKey, names[0]); //项目当前文件中的配置版本
                        isSuccess = true;
                    }
                }
                else
                {
                    Log.ConfigLoader.Error("拷贝文件失败 请检查Configs文件夹是否有配置文件");
                }

                if (!isSuccess)
                {
                    _initConfigErrorCount++;
                }

                CheckConfigFile(callback);
            });
        }

        /// <summary>
        ///     下载配置文件
        /// </summary>
        private void DownloadConfig(UnityAction<ConfigLoaderState> callback)
        {
            FileNetworkManager.Instance.ReadData($"{_cdnUrl}/config/{_cdnConfigFileName}", result =>
            {
                if (!string.IsNullOrEmpty(result))
                {
                    PlayerPrefs.SetString(ConfigFileNameKey, _cdnConfigFileName); //更新当前配置文件文件名
                    FileNetworkManager.Instance.WriteToPersistentData(FileNetworkManager.Instance.GetConfigFOlderPath(),
                        _cdnConfigFileName, result);
                    ReloadConfig(result, callback);
                }
                else
                {
                    _initConfigErrorCount++;
                    Log.ConfigLoader.Error("下载配置文件失败");
                    ReadLocalConfig(callback);
                }
            });
        }

        /// <summary>
        ///     读取本地配置文件
        /// </summary>
        private void ReadLocalConfig(UnityAction<ConfigLoaderState> callback)
        {
            var savedCfgName = PlayerPrefs.GetString(ConfigFileNameKey);
            var path = Path.Combine(FileNetworkManager.Instance.GetConfigFOlderPath(), savedCfgName);
            FileNetworkManager.Instance.ReadData(path, result =>
            {
                if (!string.IsNullOrEmpty(result))
                {
                    ReloadConfig(result, callback);
                }
                else
                {
                    _initConfigErrorCount++;
                    Log.ConfigLoader.Error("读取本地数据异常");


                    //读取本地配置文件失败，重新从默认位置拷贝原始配置文件到配置文件夹下
                    FirstLaunchCopyConfig(callback);
                }
            });
        }

        /// <summary>
        ///     检查是否有新的配置
        /// </summary>
        /// <returns></returns>
        private bool HasNewConfig()
        {
            if (!PlayerPrefs.HasKey(ConfigFileNameKey))
            {
                return true;
            }

            var savedCfgName = PlayerPrefs.GetString(ConfigFileNameKey);
            var needDownloadConfigFile = false;

            if (!string.IsNullOrEmpty(_cdnConfigFileName))
            {
                //如果本地Player Prefs里没有保存配置文件名
                if (string.IsNullOrEmpty(savedCfgName))
                {
                    needDownloadConfigFile = true;
                }
                else
                {
                    //与CDN上的对比名称
                    if (!savedCfgName.Equals(_cdnConfigFileName))
                    {
                        needDownloadConfigFile = true;
                    }
                }
            }

            return needDownloadConfigFile;
        }

        /// <summary>
        ///     重新加载配置
        /// </summary>
        /// <param name="json"></param>
        /// <param name="callback"></param>
        private void ReloadConfig(string json, [NotNull] UnityAction<ConfigLoaderState> callback)
        {
            ValidateConfigFile(json, callback);
        }

        /// <summary>
        ///     检查json
        /// </summary>
        /// <param name="json"></param>
        /// <param name="callback"></param>
        private void ValidateConfigFile(string json, UnityAction<ConfigLoaderState> callback)
        {
            if (json.IsNullOrWhiteSpace())
            {
                callback?.Invoke(ConfigLoaderState.JsonEmptyError);
                return;
            }

            if (!json.StartsWith("{"))
            {
                var gameConfig = ConfigManager.GameConfig;
                json = Cryptor.Decrypt(json, gameConfig.packageName);
            }

            _configJson = json;
            var dictionary = SerializeHelper.ToObject<Dictionary<string, object>>(_configJson);
            _jsonDictionary = dictionary;

            _isConfigLoaded = true;
            callback?.Invoke(ConfigLoaderState.Successful);


            // ParseGameConfig(dictionary, callback);
        }


        /// <summary>
        ///     解析配置文件
        /// </summary>
        /// <param name="config">配置数据结构</param>
        /// <param name="errorCallback"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T ParseNewConfig<T>(T config, UnityAction<string, string> errorCallback = null) where T : ConfigModel
        {
            if (!_isConfigLoaded)
            {
                Log.ConfigLoader.Warning("配置文件未加载完成");
                return default;
            }

            if (_configData.TryGetValue(config.GetType(), out var obj))
            {
                Log.ConfigLoader.Warning("当前配置已经成功解析了");
                return obj as T;
            }

            return Pares(config, errorCallback) as T;
        }

        /// <summary>
        ///     解析配置文件
        /// </summary>
        /// <param name="config">配置数据结构</param>
        /// <param name="errorCallback"></param>
        /// <param name="addToConfigData">是否保存起来</param>
        /// <returns></returns>
        private ConfigModel Pares(ConfigModel config, UnityAction<string, string> errorCallback = null,
            bool addToConfigData = true)
        {
            var configModel = config.Parse(JsonDictionary);
            if (configModel != null)
            {
                if (addToConfigData)
                {
                    var type = configModel.GetType();
                    // if (!_configData.ContainsKey(type))
                    // {
                    //     _configData.Add(type, configModel);
                    // }
                    // else
                    // {
                    //     Debug.LogWarning($"请注意，重复解析配置文件{type}");
                    //     _configData[type] = configModel;
                    // }

                    _configData[type] = configModel;
                }
            }
            else
            {
                errorCallback?.Invoke(config.GetType().Name, "解析异常");
                Log.ConfigLoader.Warning("解析异常");
            }

            return configModel as ConfigModel;
        }

        /// <summary>
        ///     解析自定义名称配置文件，将配置解析为自定义名称的配置文件并保存
        /// </summary>
        /// <param name="config">配置数据结构</param>
        /// <param name="configName">数据结构类型</param>
        /// <param name="errorCallback"></param>
        /// <returns></returns>
        public bool ParesPersonalizedConfig(ConfigModel config, string configName,
            UnityAction<string, string> errorCallback = null)
        {
            if (_userDefinedConfig.ContainsKey(configName))
            {
                Log.ConfigLoader.Warning("存在相同名称的自定义配置");
                return false;
            }

            var configModel = Pares(config, errorCallback, false);
            if (configModel != null)
            {
                _userDefinedConfig.Add(configName, configModel);
                return true;
            }

            Log.ConfigLoader.Warning($"解析配置重新异常{config} {configName}");

            return false;
        }


        /// <summary>
        ///     获取自定义配置数据
        /// </summary>
        /// <param name="configName">配置名称</param>
        /// <typeparam name="T">对应数据结构</typeparam>
        /// <returns></returns>
        public T GetPersonalizedConfig<T>(string configName)
        {
            if (_userDefinedConfig.TryGetValue(configName, out var value))
            {
                if (value is T configModel)
                {
                    return configModel;
                }

                Log.ConfigLoader.Warning($"有{configName}的自定义配置，但类型不对，期望类型是{typeof(T).Name} 现有类型{value.GetType().Name} ");

                return default;
            }

            return default;
        }

        public T GetConfig<T>()
        {
            return _configData.TryGetValue(typeof(T), out var value) ? (T)value : default;
        }

        public void AddConfig(ConfigModel configModel)
        {
            var type = configModel.GetType();
            _configData[type] = configModel;
        }
    }
}
