using BingoBrain.Core;

using UnityEditor;


using UnityEngine.Events;

namespace BingoBrain.Asset
{
    using System;
    using System.Linq;
    using UnityEngine;
    using System.Collections.Generic;
    using Object = UnityEngine.Object;
    using BingoBrain.Asset.Editor;

    public class BetKit : Singleton<BetKit>
    {        private readonly Dictionary<string, Dictionary<int, string>> mGameObject2AbMap = new();

        private readonly Dictionary<string, Dictionary<int, string>> mSprite2AbMap = new();

        private readonly Dictionary<string, Dictionary<int, string>> mAudio2AbMap = new();

        private IBigose LoadAssetType { get; set; }

        public void Init(IBigose loadAssetType = null)
        {
//#if UNITY_EDITOR
            LoadAssetType = new BingoseKit();

// #else
//             LoadAssetType = loadAssetType ?? new AssetBundleKit();
// #endif
        }

        public void LoadAsset<T>(string assetUrl, string assetName, UnityAction<T> onCompleted, bool isRecord = true)
            where T : Object
        {
            if (string.IsNullOrEmpty(assetUrl) || string.IsNullOrEmpty(assetName))
            {
                Debug.LogError("AssetUrl or AssetName is Empty.");
                onCompleted?.Invoke(default);
                return;
            }

            Init();

            if (LoadAssetType == null)
            {
                Debug.LogError("Please Call LoadBox.Instance.Init() first.");
                onCompleted?.Invoke(default);
                return;
            }

            LoadAssetType.GetAsset<T>(assetUrl, assetName, (obj) =>
            {
                if (obj != null && isRecord)
                {
                    RecordGameObject(assetUrl, obj);
                }

                onCompleted?.Invoke(obj);
            });
        }

        public T LoadAsset<T>(string assetUrl, string assetName, bool isRecord = true) where T : Object
        {
            if (string.IsNullOrEmpty(assetUrl) || string.IsNullOrEmpty(assetName))
            {
                Debug.LogError("AssetUrl or AssetName is Empty.");
                return default;
            }

            Init();

            if (LoadAssetType == null)
            {
                Debug.LogError("Please Call LoadBox.Instance.Init() first.");
                return default;
            }

            var obj = LoadAssetType.GetAsset<T>(assetUrl, assetName);
            if (obj != null && isRecord)
            {
                RecordGameObject(assetUrl, obj);
            }

            return obj;
        }

        #region 加载Sprite相关

        public void LoadSprite(string assetUrl, string assetName, UnityAction<Sprite> onCompleted, bool isRecord = true)
        {
            LoadAsset(assetUrl, assetName, onCompleted, isRecord);
        }

        public Sprite LoadSprite(string assetUrl, string assetName, bool isRecord = true)
        {
            return LoadAsset<Sprite>(assetUrl, assetName, isRecord);
        }

        public void LoadSprite(string assetUrl, Action<Sprite> onCompleted)
        {
            if (string.IsNullOrEmpty(assetUrl))
            {
                Debug.LogError("AssetUrl is Empty.");
                onCompleted?.Invoke(null);
                return;
            }

            Init();

            if (LoadAssetType == null)
            {
                Debug.LogError("Please Call LoadKit.Instance.Init() first.");
                onCompleted?.Invoke(null);
                return;
            }

            string assetName;
            if (assetUrl.Contains("/"))
            {
                assetName = assetUrl.Split('/').Last();
                assetUrl = assetUrl.Replace($"/{assetName}", string.Empty);
            }
            else
            {
                assetName = assetUrl.Split('.').Last();
                assetUrl = assetUrl.Replace($".{assetName}", string.Empty);
            }

            LoadAssetType.GetAsset(assetUrl, assetName, delegate(Sprite sprite)
            {
                if (sprite != null)
                {
                    RecordSprite(assetUrl, sprite);
                }

                onCompleted?.Invoke(sprite);
            });
        }

     


        public void RecordSprite(string assetName, Sprite sprite)
        {
            if (sprite == null || string.IsNullOrEmpty(assetName))
            {
                Debug.LogError("ABName is Null or Sprite is Null");
                return;
            }

            var instanceId = sprite.GetInstanceID();
            if (mSprite2AbMap.Keys.Contains(assetName))
            {
                if (!mSprite2AbMap[assetName].Keys.Contains(instanceId))
                {
                    mSprite2AbMap[assetName].Add(instanceId, sprite.name);
                }
            }
            else
            {
                var spriteNameIns = new Dictionary<int, string> { { instanceId, sprite.name } };
                mSprite2AbMap.Add(assetName, spriteNameIns);
            }
        }



        #endregion

        #region 加载GameObject相关

        public GameObject LoadGameObject(string assetUrl, string assetName, bool isRecord = true)
        {
            return LoadAsset<GameObject>(assetUrl, assetName, isRecord);
        }


        public void LoadGameObjectAndClone(string assetUrl, string assetName,
            UnityAction<GameObject> onCompleted = null,
            Transform parent = null, bool worldPositionStays = false)
        {
            LoadAsset<GameObject>(assetUrl, assetName,
                gameObject => { InstantiateAndRecord(gameObject, parent, worldPositionStays, onCompleted); }, false);
        }


        public GameObject LoadGameObjectAndCloneSync(string assetUrl, string assetName, Transform parent = null,
            bool worldPositionStays = false)
        {
            var gameObject = LoadGameObject(assetUrl, assetName, false);
            return InstantiateAndRecord(gameObject, parent, worldPositionStays);
        }


        public void RecordGameObject(string assetName, Object gameObject)
        {
            if (gameObject == null || string.IsNullOrEmpty(assetName))
            {
                Debug.LogError("ABName is Null or Sprite is Null");
                return;
            }

            var instanceId = gameObject.GetInstanceID();
            if (mGameObject2AbMap.Keys.Contains(assetName))
            {
                if (!mGameObject2AbMap[assetName].Keys.Contains(instanceId))
                {
                    mGameObject2AbMap[assetName].Add(instanceId, gameObject.name);
                }
            }
            else
            {
                var gameNameIns = new Dictionary<int, string> { { instanceId, gameObject.name } };
                mGameObject2AbMap.Add(assetName, gameNameIns);
            }
        }


        public GameObject InstantiateAndRecord(GameObject gameObject, Transform parent = null,
            bool worldPositionStays = false, UnityAction<GameObject> onCompleted = null)
        {
            if (gameObject == null)
            {
                Debug.LogError("GameObject is Null");
                return null;
            }

            var newGameObject = parent
                ? Object.Instantiate(gameObject, parent, worldPositionStays)
                : Object.Instantiate(gameObject);

            if (newGameObject != null)
            {
                RecordCloneGameObject(gameObject, newGameObject);
            }

            onCompleted?.Invoke(newGameObject);
            return newGameObject;
        }


        private void RecordCloneGameObject(GameObject gameObject, GameObject newGameObject)
        {
            if (gameObject == null || newGameObject == null)
            {
                return;
            }

            var oldInstanceId = gameObject.GetInstanceID();
            var instanceId = newGameObject.GetInstanceID();
            foreach (var keyValuePair in mGameObject2AbMap)
            {
                if (!keyValuePair.Value.Keys.Contains(oldInstanceId) ||
                    keyValuePair.Value.Keys.Contains(instanceId)) continue;
                keyValuePair.Value.Add(instanceId, newGameObject.name);
                break;
            }
        }

        #endregion

        #region 加载声音相关

        public void LoadAudio(string assetUrl, string assetName, UnityAction<AudioClip> onCompleted)
        {
            LoadAsset(assetUrl, assetName, onCompleted);
        }


        #endregion


        public void RecycleAsset(string assetUrl, UnityAction onCompleted = null)
        {
            Init();
            if (LoadAssetType != null)
            {
                LoadAssetType.RecycleAsset(assetUrl, onCompleted);
            }
            else
            {
                Debug.LogError("Please Call LoadBox.Instance.Init() first.");
            }
        }
    }
}