﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

/// <summary>
/// Global Addressables asset cache manager that supports named groups, caching, querying, and releasing.
/// </summary>
public static class BGAddressablesAssetCache
{
    // Grouped cache dictionary (Key: group name, Value: <address -> object>)
    private static readonly Dictionary<string, Dictionary<string, Object>> _groupedCache = new();

    /// <summary>
    /// Attempts to retrieve an asset from the specified cache group.
    /// </summary>
    public static bool TryGet<T>(string group, string key, out T asset) where T : Object
    {
        asset = null;
        if (_groupedCache.TryGetValue(group, out var cache) && cache.TryGetValue(key, out var rawAsset))
        {
            asset = rawAsset as T;
            return asset != null;
        }
        return false;
    }

    /// <summary>
    /// Registers an asset into the specified cache group.
    /// </summary>
    public static void Register(string group, string key, Object asset)
    {
        if (string.IsNullOrEmpty(group) || string.IsNullOrEmpty(key) || asset == null) return;

        if (!_groupedCache.TryGetValue(group, out var cache))
        {
            cache = new Dictionary<string, Object>();
            _groupedCache[group] = cache;
        }

        if (!cache.ContainsKey(key))
        {
            cache[key] = asset;
        }
    }

    /// <summary>
    /// Releases all cached assets in the specified group.
    /// </summary>
    public static void ReleaseGroup(string group)
    {
        if (_groupedCache.TryGetValue(group, out var cache))
        {
            foreach (var asset in cache.Values)
            {
                Addressables.Release(asset);
            }
            cache.Clear();
            _groupedCache.Remove(group);
        }
    }

    /// <summary>
    /// Releases all cached assets from all groups.
    /// </summary>
    public static void ReleaseAll()
    {
        foreach (var cache in _groupedCache.Values)
        {
            foreach (var asset in cache.Values)
            {
                Addressables.Release(asset);
            }
        }
        _groupedCache.Clear();
    }

    /// <summary>
    /// Checks whether a specific address exists in the given cache group.
    /// </summary>
    public static bool Contains(string group, string key)
    {
        return _groupedCache.TryGetValue(group, out var cache) && cache.ContainsKey(key);
    }

    /// <summary>
    /// Releases a specific asset and removes it from the cache.
    /// </summary>
    public static void Release(string group, string key)
    {
        if (_groupedCache.TryGetValue(group, out var cache) && cache.TryGetValue(key, out var obj))
        {
            Addressables.Release(obj);
            cache.Remove(key);

            if (cache.Count == 0)
            {
                _groupedCache.Remove(group);
            }
        }
    }
}
