using FairyGUI;
using System.Collections.Generic;
using UnityEngine;
using XGame.Framework.Asyncs;

namespace XGame.Framework.FGUI
{
    /// <summary>
    /// 修复图集合批 参考链接:https://zhuanlan.zhihu.com/p/689636245
    /// </summary>
    internal partial class FguiModule : IGloaderHandle
    {
        public class LoadedAsset
        {
            public string addressable;
            public Sprite sprite;
            public NTexture nTexture;
        }

        /// <summary>
        /// 已加载过的资源
        /// </summary>
        private Dictionary<string, LoadedAsset> _loadedAssetsMap = new Dictionary<string, LoadedAsset>();
        /// <summary>
        /// key:sprite.texture
        /// value:NTexture 用作Sprite的root
        /// </summary>
        private Dictionary<Texture, NTexture> _textureRootMap = new Dictionary<Texture, NTexture>();

        IAsync IGloaderHandle.LoadNTexture(string addressableName)
        {
            if (_loadedAssetsMap.ContainsKey(addressableName))
            { // 已经加载完
                var asyncGroup = new AsyncGroup();
                asyncGroup.End();
                return asyncGroup;
            }
            //TODO 需要识别Sprite还是Texture
            var loadAsync = _assetModule.LoadAsync<Sprite>(addressableName);
            loadAsync.On(_ =>
            {
                var result = loadAsync.Result;
                if (result == null)
                {
                    Log.Debug($"IGloaderHandle.LoadNTexture failed. addressable:{addressableName}");
                    return;
                }
                if (CreateNTexture(addressableName, result) == false)
                { //已经有其他loader加载完成
                    _assetModule.Recycle(result);
                }
            });
            return loadAsync;
        }
        NTexture IGloaderHandle.GetNTexture(string addressableName)
        {
            if (_loadedAssetsMap.TryGetValue(addressableName, out var asset))
            {
                return asset.nTexture;
            }
            // 可能是加载失败，也可能是没有加载过
            Log.Debug($"找不到NTexture，确认IGloaderHandle.LoadNTexture是否已经加载成功. Name:{addressableName}");
            return default;
        }

        private bool CreateNTexture(string addressable, Sprite sprite)
        {
            if (_loadedAssetsMap.ContainsKey(addressable))
            { // 已经有其他loader加载完成
                return false;
            }
            if (!_textureRootMap.TryGetValue(sprite.texture, out var root))
            {
                _textureRootMap[sprite.texture] = root = new NTexture(sprite.texture);
                root.destroyMethod = DestroyMethod.None;
            }
            Rect region = sprite.textureRect;
            region.y = sprite.texture.height - region.yMax;
            var nTexture = new NTexture(root, region, false);
            //注册release事件，Gloader在Dispose时，只会触发 NGraphics.Dispose() => _texture.ReleaseRef();
            nTexture.onRelease += OnReleaseNTexture;
            nTexture.destroyMethod = DestroyMethod.None;
            _loadedAssetsMap.Add(addressable, new LoadedAsset()
            {
                addressable = addressable,
                sprite = sprite,
                nTexture = nTexture,
            });
            return true;
        }
        private bool TryGetLoadedAsset(NTexture nTexture, out LoadedAsset asset)
        {
            foreach (var item in _loadedAssetsMap)
            {
                if (item.Value.nTexture == nTexture)
                {
                    asset = item.Value;
                    return true;
                }
            }
            asset = default;
            return false;
        }
        private void OnReleaseNTexture(NTexture nTexture)
        {
            if (TryGetLoadedAsset(nTexture, out var asset))
            {
                //Log.Debug($"OnReleaseNTexture Addressable:{asset.addressable}");
                _loadedAssetsMap.Remove(asset.addressable);
                if (nTexture.root.refCount <= 0)
                {
                    _textureRootMap.Remove(asset.sprite.texture);
                }
                _assetModule.Recycle(asset.sprite);
            }
        }
        /// <summary>
        /// 清空所有Gloader加载的资源
        /// </summary>
        /// <param name="assetModule"></param>
        public void ClearGloaderAssets()
        {
            foreach (var item in _loadedAssetsMap)
            {
                _assetModule.Recycle(item.Value.sprite);
            }
            _loadedAssetsMap.Clear();
            _textureRootMap.Clear();
        }
    }
}