using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;

namespace XGame.Framework.Asset
{
    /// <summary>
    /// 克隆的资源对象回收站
    /// </summary>
    internal class AssetRecycler
    {
        /// <summary>
        /// 克隆的资源对象
        /// </summary>
        internal class CloneObject
        {
            /// <summary>
            /// 资源路径
            /// </summary>
            public string AssetName { get; private set; }
            /// <summary>
            /// 克隆对象缓存容器
            /// </summary>
            private Stack<object> objects;
            /// <summary>
            /// 缓存的数量
            /// </summary>
            public int Count => objects.Count;

            public CloneObject(string assetName)
            {
                AssetName = assetName;
                objects = new Stack<object>();
            }
            public void Push(object clone)
            {
#if UNITY_EDITOR
                if (objects.Contains(clone))
                {
                    AssetsLog.Error($"资源重复回收，请检查业务代码！！！！ AssetName：{AssetName}");
                    return;
                }
#endif
                objects.Push(clone);
            }
            public object Pop()
            {
                while (objects.Count > 0)
                {
                    var result = objects.Pop();
                    if (result is GameObject go)
                    {
                        go.transform.SetParent(null);
                        go.transform.position = Vector3.zero;
                    }
                    return result;
                }
                return null;
            }
            public void Dispose(Action<long> onDestroy = null)
            {
                foreach (var it in objects)
                {
                    var go = it as GameObject;
                    if (go != null)
                    {
                        onDestroy?.Invoke(go.GetLongHashCode());
                        Object.Destroy(go);
                    }
                }
                objects.Clear();
            }
        }

        /// <summary>
        /// 缓存容器
        /// </summary>
        private Dictionary<string, CloneObject> cloneObjectMap;

        /// <summary>
        /// 回收的对象的父节点
        /// </summary>
        private Transform _recycleRoot;

        private Transform RecycleRoot
        {
            get
            {
                if (_recycleRoot == null)
                {
                    if (Application.isPlaying)
                    {
                        var go = GameObject.Find("RecycleRoot");
                        if (go == null)
                        {
                            go = new GameObject("RecycleRoot");
                            Object.DontDestroyOnLoad(go);
                        }

                        _recycleRoot = go.transform;
                    }
                }
                return _recycleRoot;
            }
        }



        public AssetRecycler()
        {
            cloneObjectMap = new Dictionary<string, CloneObject>();
            
        }

        public void Push(object clone, string addressableName)
        {
            Assert.IsNotNull(clone, $"Recycle a invalid asset. Name:{addressableName}");

            var go = clone as GameObject;
            if (go != null)
            {
                go.SetActive(false);
                if (RecycleRoot != null)
                {
                    //传false，保持localScale等参数不变，否则UI预制会被按比例缩放
                    go.transform.SetParent(_recycleRoot, false);
                    go.transform.position = Vector3.one * 10000;
                }
                else if (Application.isPlaying)
                {
                    Debug.LogError($"Asset Recycler can't find root.");
                }
            }
            CloneObject cloneObject;
            if (!cloneObjectMap.TryGetValue(addressableName, out cloneObject))
            {
                cloneObject = new CloneObject(addressableName);
                cloneObjectMap.Add(addressableName, cloneObject);
            }
            cloneObject.Push(clone);
        }

        public object Pop(string addressableName)
        {
            if (cloneObjectMap.TryGetValue(addressableName, out CloneObject obj))
            {
                return obj.Pop();
            }
            return null;
        }

        public int GetCount(string addressableName)
        {
            if (cloneObjectMap.TryGetValue(addressableName, out CloneObject obj))
            {
                return obj.Count;
            }
            return 0;
        }
        public void Dispose()
        {
            foreach (var it in cloneObjectMap)
            {
                it.Value.Dispose();
            }
            cloneObjectMap.Clear();
        }

        public void Destroy(string addressableName, Action<long> onDestroy = null)
        {
            if (cloneObjectMap.TryGetValue(addressableName, out CloneObject obj))
            {
                obj.Dispose(onDestroy);
                cloneObjectMap.Remove(addressableName);
            }
        }
    }
}

