using System;
using System.Collections.Generic;
using System.Linq;
using MCPForUnity.Editor.Helpers;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
using Unity.Profiling;
using Unity.Profiling.LowLevel.Unsafe;
using UnityEngine.Profiling;
using UProfiler = UnityEngine.Profiling.Profiler;

namespace MCPForUnity.Editor.Tools.Graphics
{
    internal static class RenderingStatsOps
    {
        private static readonly (string counterName, string jsonKey)[] COUNTER_MAP = new[]
        {
            ("Draw Calls Count", "draw_calls"),
            ("Batches Count", "batches"),
            ("SetPass Calls Count", "set_pass_calls"),
            ("Triangles Count", "triangles"),
            ("Vertices Count", "vertices"),
            ("Dynamic Batches Count", "dynamic_batches"),
            ("Dynamic Batched Draw Calls Count", "dynamic_batched_draw_calls"),
            ("Static Batches Count", "static_batches"),
            ("Static Batched Draw Calls Count", "static_batched_draw_calls"),
            ("Instanced Batches Count", "instanced_batches"),
            ("Instanced Batched Draw Calls Count", "instanced_batched_draw_calls"),
            ("Shadow Casters Count", "shadow_casters"),
            ("Render Textures Count", "render_textures"),
            ("Render Textures Bytes", "render_textures_bytes"),
            ("Used Textures Count", "used_textures"),
            ("Used Textures Bytes", "used_textures_bytes"),
            ("Render Textures Changes Count", "render_target_changes"),
            ("Visible Skinned Meshes Count", "visible_skinned_meshes"),
        };

        // === stats_get ===
        internal static object GetStats(JObject @params)
        {
            var stats = new Dictionary<string, object>();

            foreach (var (counterName, jsonKey) in COUNTER_MAP)
            {
                using var recorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, counterName);
                stats[jsonKey] = recorder.Valid ? recorder.CurrentValue : 0;
            }

            return new
            {
                success = true,
                message = "Rendering stats captured.",
                data = stats
            };
        }

        // === stats_list_counters ===
        internal static object ListCounters(JObject @params)
        {
            var p = new ToolParams(@params);
            string categoryName = p.Get("category");

            // Default to "Render" category to avoid massive payloads (all categories = 300K+ chars)
            ProfilerCategory category = ProfilerCategory.Render;
            if (!string.IsNullOrEmpty(categoryName))
            {
                category = TryResolveCategory(categoryName);
            }

            var allHandles = new List<ProfilerRecorderHandle>();
            ProfilerRecorderHandle.GetAvailable(allHandles);
            var counters = allHandles
                .Select(h => ProfilerRecorderHandle.GetDescription(h))
                .Where(d => string.Equals(d.Category.Name, category.Name, StringComparison.OrdinalIgnoreCase))
                .Select(d => new
                {
                    name = d.Name,
                    category = d.Category.Name,
                    unit = d.UnitType.ToString()
                })
                .OrderBy(c => c.name).ToList();

            return new
            {
                success = true,
                message = $"Found {counters.Count} counters in category '{category.Name}'.",
                data = new { counters }
            };
        }

        // === stats_set_scene_debug_mode ===
        internal static object SetSceneDebugMode(JObject @params)
        {
            var p = new ToolParams(@params);
            string modeName = p.Get("mode");
            if (string.IsNullOrEmpty(modeName))
            {
                var validModes = string.Join(", ", Enum.GetNames(typeof(DrawCameraMode)).Take(20));
                return new ErrorResponse(
                    $"'mode' parameter required. Options: {validModes}");
            }

            if (!Enum.TryParse<DrawCameraMode>(modeName, true, out var drawMode))
            {
                var validModes = string.Join(", ", Enum.GetNames(typeof(DrawCameraMode)).Take(20));
                return new ErrorResponse($"Unknown mode '{modeName}'. Valid: {validModes}");
            }

            var sceneView = SceneView.lastActiveSceneView;
            if (sceneView == null)
                return new ErrorResponse("No active Scene View found.");

            sceneView.cameraMode = SceneView.GetBuiltinCameraMode(drawMode);

            sceneView.Repaint();

            return new
            {
                success = true,
                message = $"Scene debug mode set to '{drawMode}'."
            };
        }

        // === stats_get_memory ===
        internal static object GetMemory(JObject @params)
        {
            var data = new Dictionary<string, object>
            {
                ["totalAllocatedMB"] = Math.Round(UProfiler.GetTotalAllocatedMemoryLong() / (1024.0 * 1024.0), 2),
                ["totalReservedMB"] = Math.Round(UProfiler.GetTotalReservedMemoryLong() / (1024.0 * 1024.0), 2),
                ["totalUnusedReservedMB"] = Math.Round(UProfiler.GetTotalUnusedReservedMemoryLong() / (1024.0 * 1024.0), 2),
                ["monoUsedMB"] = Math.Round(UProfiler.GetMonoUsedSizeLong() / (1024.0 * 1024.0), 2),
                ["monoHeapMB"] = Math.Round(UProfiler.GetMonoHeapSizeLong() / (1024.0 * 1024.0), 2),
                ["graphicsDriverMB"] = Math.Round(UProfiler.GetAllocatedMemoryForGraphicsDriver() / (1024.0 * 1024.0), 2),
            };

            return new
            {
                success = true,
                message = "Memory stats captured.",
                data
            };
        }

        // --- Helper: Try to resolve a ProfilerCategory by name ---
        private static ProfilerCategory TryResolveCategory(string name)
        {
            // ProfilerCategory has static properties for well-known categories
            switch (name.ToLowerInvariant())
            {
                case "render": return ProfilerCategory.Render;
                case "scripts": return ProfilerCategory.Scripts;
                case "memory": return ProfilerCategory.Memory;
                case "physics": return ProfilerCategory.Physics;
                case "animation": return ProfilerCategory.Animation;
                case "audio": return ProfilerCategory.Audio;
                case "lighting": return ProfilerCategory.Lighting;
                case "network": return ProfilerCategory.Network;
                case "gui": return ProfilerCategory.Gui;
                case "ai": return ProfilerCategory.Ai;
                case "video": return ProfilerCategory.Video;
                case "loading": return ProfilerCategory.Loading;
                case "input": return ProfilerCategory.Input;
                case "vr": return ProfilerCategory.Vr;
                case "internal": return ProfilerCategory.Internal;
                default: return ProfilerCategory.Render;
            }
        }
    }
}
