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

/// <summary>
/// Registre des "points de nettoyage" (callbacks) appelés sur changement de scène.
/// Objectif: offrir des points de cleanup clairs et centralisés.
/// </summary>
public sealed class CleanupPoints : MonoBehaviour
{
    private static CleanupPoints _instance;
    private static bool _isQuitting;
    public static CleanupPoints Instance
    {
        get
        {
            if (_instance != null) return _instance;
            // Pendant la fermeture (arrêt Play / quit), ne pas recréer un singleton "fantôme"
            // qui déclenche le warning Unity "Some objects were not cleaned up... CleanupPoints".
            if (_isQuitting || !Application.isPlaying) return null;
            var go = new GameObject("CleanupPoints");
            _instance = go.AddComponent<CleanupPoints>();
            DontDestroyOnLoad(go);
            return _instance;
        }
    }

    /// <summary>
    /// Retourne l'instance existante si elle existe, sans jamais en créer une nouvelle.
    /// Utile dans OnDestroy/OnDisable pour éviter de recréer CleanupPoints pendant le teardown.
    /// </summary>
    public static CleanupPoints GetExisting() => _instance;

    private readonly Dictionary<string, Action> _onSceneChange = new Dictionary<string, Action>();

    private void Awake()
    {
        if (_instance == null)
        {
            _instance = this;
            DontDestroyOnLoad(gameObject);
            SceneManager.activeSceneChanged += OnActiveSceneChanged;
        }
        else if (_instance != this)
        {
            Destroy(gameObject);
        }
    }

    private void OnApplicationQuit()
    {
        _isQuitting = true;
    }

    private void OnDestroy()
    {
        if (_instance == this)
        {
            SceneManager.activeSceneChanged -= OnActiveSceneChanged;
            _instance = null;
        }
    }

    private void OnActiveSceneChanged(Scene oldScene, Scene newScene)
    {
        foreach (var kv in _onSceneChange)
        {
            try { kv.Value?.Invoke(); }
            catch (Exception e) { Debug.LogWarning($"[CleanupPoints] Exception cleanup '{kv.Key}': {e.Message}"); }
        }

        // Nettoyage global: la mémoire WebGL est fragile.
        // ⚠️ Ne pas appeler RemoteSpriteCache.Instance ici (ça le créerait si absent).
        // Stratégie: au retour sur Main/Map, purger les caches runtime persistants pour éviter abort("OOM").
        if (newScene.name == "Main" || newScene.name == "Map")
        {
            if (RemoteSpriteCache.GetExisting() != null)
            {
                RemoteSpriteCache.GetExisting().ClearAll();
            }

            // GameDataManager est souvent DontDestroyOnLoad et peut garder des textures/sprites en cache.
            // On purge uniquement le cache d'assets (pas les données de jeu).
            if (GameDataManager.Instance != null)
            {
                GameDataManager.Instance.ClearAssetCache();
            }

#if UNITY_WEBGL && !UNITY_EDITOR
            // WebGL: tenter de relâcher un maximum avant de charger les grosses textures de Main.
            // (Oui c'est coûteux, mais mieux qu'un abort("OOM").)
            try { Resources.UnloadUnusedAssets(); } catch { }
            try { System.GC.Collect(); } catch { }
#endif
        }
    }

    /// <summary>
    /// Enregistre un callback. Un nouvel enregistrement avec la même clé remplace l'ancien.
    /// </summary>
    public void RegisterOnSceneChange(string key, Action action)
    {
        if (string.IsNullOrEmpty(key)) return;
        _onSceneChange[key] = action;
    }

    public void UnregisterOnSceneChange(string key)
    {
        if (string.IsNullOrEmpty(key)) return;
        _onSceneChange.Remove(key);
    }
}


