#nullable enable
using AdvChkSys.Constraints;
using AdvChkSys.Manager;
using AdvChkSys.Chunk;
using AdvChkSys.Resources;
using AdvChkSys.Diagnostics;
using AdvChkSys.Threading;
using AdvChkSys.Spatial;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace AdvChkSys
{
    /// <summary>
    /// Entry point and static facade for the AdvChkSys library.
    /// Provides version info, helpers for creating managers and constraints, and a basic self-test.
    /// </summary>
    public static class AdvChkSys
    {
        /// <summary>
        /// The current version of the AdvChkSys library.
        /// </summary>
        public static string Version => "0.2.0";

        /// <summary>
        /// Creates a new WorldConstraints object.
        /// </summary>
        public static WorldConstraints CreateDefaultConstraints() => new();

        /// <summary>
        /// Creates a new 2D chunk manager with optional constraints.
        /// </summary>
        public static ChunkManager2D<byte> Create2DManager(WorldConstraints? constraints = null) =>
            new(constraints);

        /// <summary>
        /// Creates a new 3D chunk manager with optional constraints.
        /// </summary>
        public static ChunkManager3D<byte> Create3DManager(WorldConstraints? constraints = null) =>
            new(constraints);

        /// <summary>
        /// Gets a detailed report of the current memory usage by the chunk system.
        /// </summary>
        /// <returns>A report containing memory usage statistics</returns>
        public static MemoryUsageReport GetMemoryUsage() => MemoryUsageReporter.GetMemoryUsage();

        /// <summary>
        /// Logs the current memory usage to the provided logging action.
        /// </summary>
        /// <param name="logAction">Action that will receive the log messages</param>
        public static void LogMemoryUsage(Action<string> logAction) =>
            MemoryUsageReporter.LogMemoryUsage(logAction);

        /// <summary>
        /// Gets the threading manager for advanced threading operations.
        /// </summary>
        public static ChunkThreadingManager ThreadingManager => ChunkThreadingManager.Instance;

        /// <summary>
        /// Runs a batch of chunk operations in parallel.
        /// </summary>
        public static Task RunParallelChunkOperationsAsync(IEnumerable<Action> operations,
            int? maxDegreeOfParallelism = null,
            CancellationToken cancellationToken = default)
        {
            return ChunkTaskScheduler.RunBatchParallelAsync(operations, maxDegreeOfParallelism, cancellationToken);
        }

        /// <summary>
        /// Creates a spatial index for 2D chunks.
        /// </summary>
        public static SpatialChunkIndex<Chunk2D<T>> CreateSpatialIndex2D<T>() =>
            new();

        /// <summary>
        /// Creates a spatial index for 3D chunks.
        /// </summary>
        public static SpatialChunkIndex<Chunk3D<T>> CreateSpatialIndex3D<T>() =>
            new();

        /// <summary>
        /// Configures the threading system for high throughput.
        /// </summary>
        public static void ConfigureForHighThroughput() =>
            ChunkThreadingConfiguration.ConfigureForHighThroughput();

        /// <summary>
        /// Configures the threading system for low latency.
        /// </summary>
        public static void ConfigureForLowLatency() =>
            ChunkThreadingConfiguration.ConfigureForLowLatency();

        /// <summary>
        /// Configures the threading system for memory efficiency.
        /// </summary>
        public static void ConfigureForMemoryEfficiency() =>
            ChunkThreadingConfiguration.ConfigureForMemoryEfficiency();

        /// <summary>
        /// Performs a basic self-test of the AdvChkSys core functionality.
        /// Returns true if all core systems are operational.
        /// </summary>
        public static bool SelfTest()
        {
            // Create constraints
            var constraints = new WorldConstraints
            {
                MinChunkX = 0,
                MinChunkY = 0,
                MaxChunkX = 2,
                MaxChunkY = 2,
                MaxLoadedChunks = 4
            };

            // Create managers
            var manager2D = new ChunkManager2D<byte>(constraints);
            var manager3D = new ChunkManager3D<byte>(constraints);

            // Test 2D chunk creation
            var chunk2D = manager2D.LoadOrCreateChunk(1, 1, 8, 8);
            chunk2D[0, 0] = 42;

            // Test 3D chunk creation
            var chunk3D = manager3D.LoadOrCreateChunk(1, 1, 1, 4, 4, 4);
            chunk3D[0, 0, 0] = 99;

            // Check resource manager tracking
            bool resourceTracking2D = ChunkResourceManager.AllocatedChunkCount >= 1;
            bool resourceTracking3D = ChunkResourceManager.AllocatedChunkCount >= 2;

            // Check constraints enforcement
            bool constraintsWork = constraints.IsWithinBounds(1, 1) && constraints.IsWithinChunkLimit(2);

            // Test spatial indexing
            var spatialIndex2D = CreateSpatialIndex2D<byte>();
            spatialIndex2D.AddChunk(chunk2D);
            var chunksInRegion = spatialIndex2D.FindChunksInRegion(0, 0, 2, 2);
            bool spatialIndexWorks = false;
            foreach (var c in chunksInRegion)
            {
                if (c.Equals(chunk2D))
                {
                    spatialIndexWorks = true;
                    break;
                }
            }

            // Test threading
            bool threadingWorks = ThreadingManager != null;

            // Clean up
            manager2D.UnloadChunk(1, 1);
            manager3D.UnloadChunk(1, 1, 1);

            return resourceTracking2D && resourceTracking3D && constraintsWork &&
                   spatialIndexWorks && threadingWorks;
        }
    }
}