using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace SFramework
{
    public class SResourceManager
    {
        private static AssetBundleManifest _mainAssetBundleManifest = null;
        private static Dictionary<string, AssetBundle> _loadedAssetBundle = new Dictionary<string, AssetBundle>();

        public static string TestCall(string value)
        {
            Debug.Log("SFramework.SResourceManager.TestCall -> " + value);

            return "TestCall Return Value.";
        }

        public static UnityEngine.Object LoadResource(string resourcePath)
        {
            UnityEngine.Object targetObject = null;
            resourcePath = resourcePath.ToLower();
#pragma warning disable 0162
            // Editor Direct Read Res
            if (Application.isEditor && !SFrameworkDef.isLoadAssetsBundleOnEditor)
            {
                string resFinalPath = "";
#if UNITY_EDITOR
                resFinalPath = "Assets/" + SFrameworkDef.ResourceDir + "/" + resourcePath;
                targetObject = UnityEditor.AssetDatabase.LoadAssetAtPath(resFinalPath, typeof(UnityEngine.Object));
                Debug.Assert(targetObject != null);
#endif
                return targetObject;
            }
#pragma warning restore 0162
            // Editor or non-Editor Read AssetsBundle
            else
            {
                // Check Main AssetBundleManifest.
                if (_mainAssetBundleManifest == null)
                {
                    LoadMainAssetBundleManifest();
                }

                string abExtName = SFrameworkDef.AssetsBundleExtName;
                targetObject = LoadOneAssetBundle(resourcePath + abExtName);
                // Disable it on 20220325 by Jiang XuFeng. Because targeetObject == null. If the assetbundle.isStreamedSceneAssetBundle == true.
                // Debug.Assert(targetObject != null);

                return targetObject;
            }
        }

        private static void LoadMainAssetBundleManifest()
        {
            string mainManifestPath = "";
            string platformName = SPlatformInfo.GetBuildPlatformName();
            string persistentPath = Application.persistentDataPath + "/Bundles/" + platformName + "/" + platformName;
            string streamingPath = Application.streamingAssetsPath + "/Bundles/" + platformName + "/" + platformName;

            // Process Special Android Path.
            if (platformName == "Android" && !Application.isEditor)
            {
                streamingPath = Application.dataPath + "!assets/Bundles/" + platformName + "/" + platformName;
                mainManifestPath = streamingPath;
            }

            if (System.IO.File.Exists(streamingPath))
                mainManifestPath = streamingPath;

            if (System.IO.File.Exists(persistentPath))
                mainManifestPath = persistentPath;

            if (string.IsNullOrEmpty(mainManifestPath))
            {
                Debug.LogError(string.Format("LoadMainAssetBundleManifest Failed ! File:{0} Is Not Existed!", mainManifestPath));
                return;
            }
            Debug.Log("LoadMainAssetBundleManifest -> mainManifestPath -> " + mainManifestPath);

            AssetBundle manifestAB = AssetBundle.LoadFromFile(mainManifestPath);
            Debug.Assert(mainManifestPath != null);
            _mainAssetBundleManifest = manifestAB.LoadAsset("AssetBundleManifest") as AssetBundleManifest;
            Debug.Assert(_mainAssetBundleManifest != null);
            Debug.Log("LoadMainAssetBundleManifest Success!");
        }

        private static UnityEngine.Object LoadOneAssetBundle(string assetBundleFullName)
        {
            Debug.Assert(_mainAssetBundleManifest != null);

            UnityEngine.Object targetObject;
            string resourcePath = "";
            string platformName = SPlatformInfo.GetBuildPlatformName();
            string persistentPath = Application.persistentDataPath + "/Bundles/" + platformName + "/" + assetBundleFullName;
            string streamingPath = Application.streamingAssetsPath + "/Bundles/" + platformName + "/" + assetBundleFullName;
            string assetName = GetAssetNameByAssetBundleFullName(assetBundleFullName);

            // Process Loaded Asset Bundle.
            if (_loadedAssetBundle.ContainsKey(assetBundleFullName))
            {
                AssetBundle loadedAB = _loadedAssetBundle[assetBundleFullName];
                Debug.Assert(loadedAB != null);
                targetObject = loadedAB.LoadAsset(assetName);
                Debug.Assert(targetObject != null);
                Debug.Log(string.Format("LoadOneAssetBundle -> Load By Cache AsetName:{0} From:{1}", assetName, assetBundleFullName));
                return targetObject;
            }

            // Process Special Android Path.
            if (platformName == "Android" && !Application.isEditor)
            {
                streamingPath = Application.dataPath + "!assets/Bundles/" + platformName + "/" + assetBundleFullName;
                resourcePath = streamingPath;
            }

            // For Editor Link.
            if (System.IO.File.Exists(streamingPath))
                resourcePath = streamingPath;

            if (System.IO.File.Exists(persistentPath))
                resourcePath = persistentPath;

            if (string.IsNullOrEmpty(resourcePath))
            {
                Debug.LogError(string.Format("LoadOneAssetBundle Failed ! File:{0} Is Not Existed!", assetBundleFullName));
                return null;
            }
            //Debug.Log("LoadOneAssetBundle -> resourcePath -> " + resourcePath);

            // Load All Dependencies
            string[] dependenciesArray = _mainAssetBundleManifest.GetAllDependencies(assetBundleFullName);
            for (var depIndex = 0; depIndex < dependenciesArray.Length; depIndex++)
                LoadOneAssetBundle(dependenciesArray[depIndex]);

            // Load AssetBundle
            AssetBundle resourceAB = AssetBundle.LoadFromFile(resourcePath);
            Debug.Assert(resourceAB != null);
            if (resourceAB.isStreamedSceneAssetBundle)
            {
                // isStreamedSceneAssetBundle Can't Be LoadAsset.
                // just can load like below.
                // string[] scenePath = resourceAB.GetAllScenePaths();
                // string sceneName = System.IO.Path.GetFileNameWithoutExtension(scenePath[0]);
                // UnityEngine.SceneManagement.Scene targetScene = UnityEngine.SceneManagement.SceneManager.GetSceneByName(sceneName);
                // UnityEngine.SceneManagement.SceneManager.LoadScene(sceneName);
                // targetObject = targetScene as UnityEngine.Object;
                targetObject = null;
            }
            else 
            {
                targetObject = resourceAB.LoadAsset(assetName);
                Debug.Assert(targetObject != null);
            }

            _loadedAssetBundle.Add(assetBundleFullName, resourceAB);
            Debug.Log(string.Format("LoadOneAssetBundle -> Load By File AssetName:{0} From:{1}", assetName, assetBundleFullName));

            return targetObject;
        }

        private static string GetAssetNameByAssetBundleFullName(string assetBundleFullName)
        {
            string[] splitArray = assetBundleFullName.Split('/');
            string splitString = splitArray[splitArray.Length - 1];

            int extNameLengh = SFrameworkDef.AssetsBundleExtName.Length;
            string finalString = splitString.Substring(0, splitString.Length - extNameLengh);

            return finalString;
        }

        private static string GetAssetNameByAssetBundleFullNameWithExt(string assetBundleFullName)
        {
            string[] splitArray = assetBundleFullName.Split('/');
            string splitString = splitArray[splitArray.Length - 1];
            string finalString = splitString;

            return finalString;
        }

        public static SFramework.SVersionInfo GetLocalVersionInfo()
        {
            var platformName = SPlatformInfo.GetBuildPlatformName();
            string persistentPath = Application.persistentDataPath + "/Bundles/" + platformName + "/" + SFrameworkDef.VersionFileName;
            string streamingPath = Application.streamingAssetsPath + "/Bundles/" + platformName + "/" + SFrameworkDef.VersionFileName;
            string versionFilePath = "";
            bool canLoadFromFileDirectly = false;

            // Process Special Android Real Machine Path.
            if (platformName == "Android" && !Application.isEditor)
            {
                streamingPath = "jar:file://" + Application.dataPath + "!assets/Bundles/" + platformName + "/" + SFrameworkDef.VersionFileName;
                versionFilePath = streamingPath;
                canLoadFromFileDirectly = false;
            }

            // For Editor Link.
            if (System.IO.File.Exists(streamingPath))
            {
                versionFilePath = streamingPath;
                canLoadFromFileDirectly = true;
            }

            Debug.Log("persistentPath -> " + persistentPath);
            if (System.IO.File.Exists(persistentPath))
            {
                versionFilePath = persistentPath;
                canLoadFromFileDirectly = true;
            }

            if (string.IsNullOrEmpty(versionFilePath))
            {
                Debug.LogError(string.Format("GetLocalVersionInfo Failed ! File:{0} Is Not Existed!", versionFilePath));
                return null;
            }
            Debug.Log("GetLocalVersionInfo -> File Path -> " + versionFilePath);

            string versionInfo = "";
            if (canLoadFromFileDirectly)
            {
                versionInfo = System.IO.File.ReadAllText(versionFilePath);
            }
            else
            {
                UnityEngine.Networking.UnityWebRequest versionFileLoader =
                    UnityEngine.Networking.UnityWebRequest.Get(versionFilePath);
                versionFileLoader.timeout = 3;
                versionFileLoader.SendWebRequest();
                while (!versionFileLoader.isDone)
                {
                    // just wait.
                }
                //if (versionFileLoader.isNetworkError || versionFileLoader.isHttpError)
                if (versionFileLoader.result == UnityEngine.Networking.UnityWebRequest.Result.ConnectionError || versionFileLoader.result == UnityEngine.Networking.UnityWebRequest.Result.ProtocolError)
                {
                    Debug.LogError("GetLocalVersionInfo -> versionFileLoader error ->" + versionFileLoader.error);
                    return null;
                }
                versionInfo = versionFileLoader.downloadHandler.text;
            }


            SVersionInfo localVersionInfo =  LitJson.JsonMapper.ToObject<SVersionInfo>(versionInfo);
            Debug.Assert(localVersionInfo != null);

            return localVersionInfo;
        }

        public static void TryDeleteAssetBundle(string assetBundleName)
        {
            // Here the assetBundleName include ext name , Like -> "prefabs/xxxx.prefab.s"
            string platformName = SPlatformInfo.GetBuildPlatformName();
            string filePath = Application.persistentDataPath + "/Bundles/" + platformName + "/" + assetBundleName;
            string fileManifesetPath = filePath + ".manifest";

            // Delete AssetBundle File.
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
                Debug.Log(string.Format("TryDeleteAssetBundle -> Delete File:{0} Path:{1}", assetBundleName, filePath));
            }

            // Delete AssetBundle.manifest File.
            if (System.IO.File.Exists(fileManifesetPath))
            {
                System.IO.File.Delete(fileManifesetPath);
                Debug.Log(string.Format("TryDeleteAssetBundle -> Delete File:{0} Path:{1}", assetBundleName + ".manifest", filePath));
            }
        }

        public static void SaveAssetBundle(string assetBundleName, byte[] assetBundleData)
        {
            string platformName = SPlatformInfo.GetBuildPlatformName();
            string abFullPathWithName = Application.persistentDataPath + "/Bundles/" + platformName + "/" + assetBundleName;
            string abFullPath = SToolFunction.GetAssetBundleFullPath(abFullPathWithName);

            // Debug.Log("abFullPathWithName -> " + abFullPathWithName);
            // Debug.Log("abFullPath -> " + abFullPath);
            SToolFunction.MakeSurePathExisted(abFullPath);

            System.IO.File.WriteAllBytes(abFullPathWithName, assetBundleData);

            // Below is wrong. file size error.
            // System.IO.StreamWriter abWriter = new System.IO.StreamWriter(abFullPathWithName);
            // abWriter.Write(assetBundleData);
            // abWriter.Close();
            // abWriter.Dispose();
            Debug.Log(string.Format(
                "SResourceManager -> SaveAssetBundle abName:{0} abPath:{1}", assetBundleName, abFullPathWithName
            ));
        }

        public static void SaveRemoteVersion(SVersionInfo remoteVersion)
        {
            string platformName = SPlatformInfo.GetBuildPlatformName();
            string versionPath = Application.persistentDataPath + "/Bundles/" + platformName + "/";
            string jsonInfo = LitJson.JsonMapper.ToJson(remoteVersion);

            SToolFunction.MakeSurePathExisted(versionPath);
            versionPath += SFrameworkDef.VersionFileName;

            System.IO.StreamWriter versionWriter = new System.IO.StreamWriter(versionPath);
            versionWriter.Write(jsonInfo);
            versionWriter.Close();
            versionWriter.Dispose();

            Debug.Log(string.Format(
                "SResourceManager -> SaveRemoteVersion -> SavePath:{0} VersionInfo:{1}", versionPath, jsonInfo
            ));
        }

    }
}

