#nullable enable
using System;
using System.Threading;

namespace AdvChkSys.Events
{
    /// <summary>
    /// Provides events for chunk lifecycle operations such as loading, unloading, saving, and more.
    /// Thread-safe event subscription and invocation.
    /// </summary>
    public static class ChunkEvents
    {
        // Backing fields for thread-safe event handling
        private static Action<Interfaces.IChunk>? _chunkLoaded;
        private static Action<Interfaces.IChunk>? _chunkUnloaded;
        private static Action<Interfaces.IChunk>? _chunkLoading;
        private static Action<Interfaces.IChunk>? _chunkUnloading;
        private static Action<Interfaces.IChunk>? _chunkSaving;
        private static Action<Interfaces.IChunk>? _chunkSaved;

        /// <summary>
        /// Occurs when a chunk has been loaded into memory.
        /// </summary>
        public static event Action<Interfaces.IChunk> ChunkLoaded
        {
            add => AddHandler(ref _chunkLoaded, value);
            remove => RemoveHandler(ref _chunkLoaded, value);
        }

        /// <summary>
        /// Occurs when a chunk is about to be loaded into memory.
        /// </summary>
        public static event Action<Interfaces.IChunk> ChunkLoading
        {
            add => AddHandler(ref _chunkLoading, value);
            remove => RemoveHandler(ref _chunkLoading, value);
        }

        /// <summary>
        /// Occurs when a chunk is about to be unloaded from memory.
        /// </summary>
        public static event Action<Interfaces.IChunk> ChunkUnloading
        {
            add => AddHandler(ref _chunkUnloading, value);
            remove => RemoveHandler(ref _chunkUnloading, value);
        }

        /// <summary>
        /// Occurs when a chunk has been unloaded from memory.
        /// </summary>
        public static event Action<Interfaces.IChunk> ChunkUnloaded
        {
            add => AddHandler(ref _chunkUnloaded, value);
            remove => RemoveHandler(ref _chunkUnloaded, value);
        }

        /// <summary>
        /// Occurs when a chunk is about to be saved.
        /// </summary>
        public static event Action<Interfaces.IChunk> ChunkSaving
        {
            add => AddHandler(ref _chunkSaving, value);
            remove => RemoveHandler(ref _chunkSaving, value);
        }

        /// <summary>
        /// Occurs when a chunk has been saved.
        /// </summary>
        public static event Action<Interfaces.IChunk> ChunkSaved
        {
            add => AddHandler(ref _chunkSaved, value);
            remove => RemoveHandler(ref _chunkSaved, value);
        }

        /// <summary>
        /// Raises the ChunkLoading event.
        /// </summary>
        public static void OnChunkLoading(Interfaces.IChunk chunk) => _chunkLoading?.Invoke(chunk);

        /// <summary>
        /// Raises the ChunkLoaded event.
        /// </summary>
        public static void OnChunkLoaded(Interfaces.IChunk chunk) => _chunkLoaded?.Invoke(chunk);

        /// <summary>
        /// Raises the ChunkUnloading event.
        /// </summary>
        public static void OnChunkUnloading(Interfaces.IChunk chunk) => _chunkUnloading?.Invoke(chunk);

        /// <summary>
        /// Raises the ChunkUnloaded event.
        /// </summary>
        public static void OnChunkUnloaded(Interfaces.IChunk chunk) => _chunkUnloaded?.Invoke(chunk);

        /// <summary>
        /// Raises the ChunkSaving event.
        /// </summary>
        public static void OnChunkSaving(Interfaces.IChunk chunk) => _chunkSaving?.Invoke(chunk);

        /// <summary>
        /// Raises the ChunkSaved event.
        /// </summary>
        public static void OnChunkSaved(Interfaces.IChunk chunk) => _chunkSaved?.Invoke(chunk);

        // Thread-safe add/remove for event handlers
        private static void AddHandler(ref Action<Interfaces.IChunk>? field, Action<Interfaces.IChunk> handler)
        {
            Action<Interfaces.IChunk>? prevHandler, newHandler;
            do
            {
                prevHandler = field;
                newHandler = (Action<Interfaces.IChunk>?)Delegate.Combine(prevHandler, handler);
            } while (Interlocked.CompareExchange(ref field, newHandler, prevHandler) != prevHandler);
        }

        private static void RemoveHandler(ref Action<Interfaces.IChunk>? field, Action<Interfaces.IChunk> handler)
        {
            Action<Interfaces.IChunk>? prevHandler, newHandler;
            do
            {
                prevHandler = field;
                newHandler = (Action<Interfaces.IChunk>?)Delegate.Remove(prevHandler, handler);
            } while (Interlocked.CompareExchange(ref field, newHandler, prevHandler) != prevHandler);
        }
    }
}