/*
 * OptimizedColliderTool.cs
 * 
 * A production-ready Unity Editor tool for intelligent collider generation.
 * Features:
 * - OBB (Oriented Bounding Box) fitting for accurate building structure following
 * - Mesh decimation for optimized MeshColliders
 * - Compound collider generation for complex buildings
 * - Terrain/ground detection and configuration
 * - Memory optimization and performance profiling
 * - Gap detection and filling
 * 
 * Created: 2026-01-15
 */

using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace OptimizedColliders
{
    /// <summary>
    /// Main editor window for the Optimized Collider Tool
    /// </summary>
    public class OptimizedColliderTool : EditorWindow
    {
        #region Serialized Fields and Settings
        
        // Object assignments
        private GameObject environmentParent;
        private GameObject groundTerrain;
        private GameObject groundReference; // Reference ground for component copying
        
        // Generation method
        public enum ColliderMethod
        {
            MeshCollider,
            BoxColliderAutoFit,
            CompoundColliders,
            ConvexMesh,
            Adaptive // Auto-select best method per object
        }
        private ColliderMethod colliderMethod = ColliderMethod.Adaptive;
        
        // Detail level
        public enum DetailLevel
        {
            Low = 0,    // 100-500 triangles, fastest
            Medium = 1, // 500-2000 triangles, balanced
            High = 2    // 2000-5000 triangles, accurate
        }
        private DetailLevel detailLevel = DetailLevel.Medium;
        
        // Options
        private bool generateForBuildings = true;
        private bool generateForGround = true;
        private bool generateForVegetation = false;
        private bool generateForProps = true;
        private bool optimizeForPerformance = true;
        private bool createCompoundForComplex = false; // OFF by default - creates too many colliders
        private bool removeExistingFirst = true; // ON by default for clean runs
        private bool skipGroundPlanes = true; // ON by default - terrain collider is sufficient, planes under buildings create invisible walls
        
        // Minimum size filter - objects smaller than this get NO collider
        private float minimumObjectSize = 0.5f; // Objects smaller than 0.5m in all dimensions get skipped
        
        // Advanced settings
        private bool showAdvancedSettings = false;
        private float colliderOverlap = 0.02f; // 2cm overlap to prevent gaps
        private int maxTrianglesLow = 500;
        private int maxTrianglesMedium = 2000;
        private int maxTrianglesHigh = 5000;
        private int complexityThreshold = 8; // Child renderer count threshold
        private int vertexThreshold = 3000;  // Vertex count threshold for complex buildings
        private bool useOBBFitting = true;   // Use OBB instead of AABB
        private bool detectArchitecturalFeatures = true;
        private bool fillGaps = true;
        private float gapDetectionSpacing = 0.5f;
        private int groundLayer = 8; // Default to layer 8 (from terrain analysis)
        private bool markAsStatic = true;
        private bool bakeMeshColliders = true;
        
        // State
        private Vector2 scrollPosition;
        private bool isProcessing = false;
        private float progress = 0f;
        private string statusMessage = "";
        private List<AnalysisResult> analysisResults = new List<AnalysisResult>();
        private List<string> logMessages = new List<string>();
        private ColliderStatistics statistics = new ColliderStatistics();
        
        // Undo tracking
        private List<ColliderChangeRecord> changeRecords = new List<ColliderChangeRecord>();
        
        // Cached styles
        private GUIStyle headerStyle;
        private GUIStyle sectionStyle;
        private GUIStyle logStyle;
        private bool stylesInitialized = false;
        
        #endregion
        
        #region Data Classes
        
        [System.Serializable]
        public class AnalysisResult
        {
            public GameObject gameObject;
            public string objectType; // Building, Ground, Prop, Vegetation, etc.
            public string recommendedCollider;
            public string reason;
            public int vertexCount;
            public int triangleCount;
            public Vector3 bounds;
            public float complexity; // 0-1 complexity score
            public bool selected = true;
            public Color displayColor = Color.green;
        }
        
        [System.Serializable]
        public class ColliderStatistics
        {
            public int totalObjects;
            public int objectsWithColliders;
            public int objectsNeedingColliders;
            public int buildingCount;
            public int groundCount;
            public int propCount;
            public int vegetationCount;
            public long estimatedMemoryBytes;
            public long originalMeshMemoryBytes;
            public int totalTriangles;
            public int optimizedTriangles;
            
            public void Reset()
            {
                totalObjects = 0;
                objectsWithColliders = 0;
                objectsNeedingColliders = 0;
                buildingCount = 0;
                groundCount = 0;
                propCount = 0;
                vegetationCount = 0;
                estimatedMemoryBytes = 0;
                originalMeshMemoryBytes = 0;
                totalTriangles = 0;
                optimizedTriangles = 0;
            }
        }
        
        [System.Serializable]
        public class ColliderChangeRecord
        {
            public GameObject target;
            public Collider addedCollider;
            public GameObject addedChild; // For compound colliders
            public StaticEditorFlags previousFlags;
            public bool flagsChanged;
        }
        
        /// <summary>
        /// Detected architectural feature (wall, floor, roof, etc.)
        /// </summary>
        public struct ArchitecturalFeature
        {
            public Vector3 center;
            public Vector3 size;
            public Quaternion rotation;
            public string featureType; // Wall, Floor, Roof, Column, etc.
            public Vector3 normal;
        }
        
        #endregion
        
        #region Menu and Window
        
        [MenuItem("Tools/Optimized Collider Tool")]
        public static void ShowWindow()
        {
            var window = GetWindow<OptimizedColliderTool>("Optimized Colliders");
            window.minSize = new Vector2(500, 700);
        }
        
        private void OnEnable()
        {
            stylesInitialized = false;
        }
        
        private void InitializeStyles()
        {
            if (stylesInitialized) return;
            
            headerStyle = new GUIStyle(EditorStyles.boldLabel)
            {
                fontSize = 16,
                alignment = TextAnchor.MiddleCenter,
                normal = { textColor = new Color(0.9f, 0.9f, 0.9f) }
            };
            
            sectionStyle = new GUIStyle(EditorStyles.boldLabel)
            {
                fontSize = 13,
                normal = { textColor = new Color(0.8f, 0.9f, 1f) }
            };
            
            logStyle = new GUIStyle(EditorStyles.miniLabel)
            {
                wordWrap = true,
                richText = true,
                normal = { textColor = new Color(0.7f, 0.7f, 0.7f) }
            };
            
            stylesInitialized = true;
        }
        
        #endregion
        
        #region Main GUI
        
        private void OnGUI()
        {
            InitializeStyles();
            
            // Header
            DrawHeader();
            
            // Play mode check
            if (Application.isPlaying)
            {
                EditorGUILayout.HelpBox("Exit Play Mode to use this tool.", MessageType.Warning);
                return;
            }
            
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            
            // Environment Setup Section
            DrawEnvironmentSetup();
            
            // Generation Settings Section
            DrawGenerationSettings();
            
            // Options Section
            DrawOptions();
            
            // Advanced Settings Section
            DrawAdvancedSettings();
            
            // Action Buttons
            DrawActionButtons();
            
            // Progress Bar
            if (isProcessing)
            {
                DrawProgressBar();
            }
            
            // Analysis Results Section
            if (analysisResults.Count > 0)
            {
                DrawAnalysisResults();
            }
            
            // Statistics Section
            if (statistics.totalObjects > 0)
            {
                DrawStatistics();
            }
            
            // Log Section
            DrawLogSection();
            
            EditorGUILayout.EndScrollView();
        }
        
        private void DrawHeader()
        {
            var headerRect = EditorGUILayout.GetControlRect(false, 45);
            EditorGUI.DrawRect(headerRect, new Color(0.15f, 0.25f, 0.35f, 0.9f));
            GUI.Label(headerRect, "🔧 Optimized Collider Tool", headerStyle);
            GUILayout.Space(10);
        }
        
        private void DrawEnvironmentSetup()
        {
            EditorGUILayout.BeginVertical("box");
            GUILayout.Label("📁 Environment Setup", sectionStyle);
            GUILayout.Space(5);
            
            environmentParent = (GameObject)EditorGUILayout.ObjectField(
                new GUIContent("Environment Parent", "Root GameObject containing all buildings and objects"),
                environmentParent, typeof(GameObject), true);
            
            groundTerrain = (GameObject)EditorGUILayout.ObjectField(
                new GUIContent("Ground/Terrain", "Terrain or ground mesh GameObject"),
                groundTerrain, typeof(GameObject), true);
            
            groundReference = (GameObject)EditorGUILayout.ObjectField(
                new GUIContent("Ground Reference (Optional)", "Working ground example to copy components from"),
                groundReference, typeof(GameObject), true);
            
            if (environmentParent == null)
            {
                EditorGUILayout.HelpBox("Assign the Environment Parent GameObject to begin analysis.", MessageType.Info);
            }
            
            EditorGUILayout.EndVertical();
            GUILayout.Space(8);
        }
        
        private void DrawGenerationSettings()
        {
            EditorGUILayout.BeginVertical("box");
            GUILayout.Label("⚙️ Generation Settings", sectionStyle);
            GUILayout.Space(5);
            
            colliderMethod = (ColliderMethod)EditorGUILayout.EnumPopup(
                new GUIContent("Collider Method", "How to generate colliders"),
                colliderMethod);
            
            detailLevel = (DetailLevel)EditorGUILayout.EnumPopup(
                new GUIContent("Detail Level", "Affects memory vs accuracy trade-off"),
                detailLevel);
            
            // Show detail level info
            string detailInfo = detailLevel switch
            {
                DetailLevel.Low => "Fast, ~100-500 triangles per collider",
                DetailLevel.Medium => "Balanced, ~500-2000 triangles per collider",
                DetailLevel.High => "Accurate, ~2000-5000 triangles per collider",
                _ => ""
            };
            EditorGUILayout.LabelField("", detailInfo, EditorStyles.miniLabel);
            
            EditorGUILayout.EndVertical();
            GUILayout.Space(8);
        }
        
        private void DrawOptions()
        {
            EditorGUILayout.BeginVertical("box");
            GUILayout.Label("☑️ Options", sectionStyle);
            GUILayout.Space(5);
            
            EditorGUILayout.LabelField("Object Categories", EditorStyles.boldLabel);
            generateForBuildings = EditorGUILayout.ToggleLeft(
                new GUIContent("✅ Buildings", "Create colliders for building structures"),
                generateForBuildings);
            
            generateForGround = EditorGUILayout.ToggleLeft(
                new GUIContent("✅ Ground/Terrain", "Configure terrain or ground colliders"),
                generateForGround);
            
            generateForProps = EditorGUILayout.ToggleLeft(
                new GUIContent("✅ Props (fences, benches, etc.)", "Create colliders for props and small objects"),
                generateForProps);
            
            generateForVegetation = EditorGUILayout.ToggleLeft(
                new GUIContent("🌿 Trees & Vegetation", "Create colliders for vegetation (usually not needed)"),
                generateForVegetation);
            
            GUILayout.Space(5);
            EditorGUILayout.LabelField("Ground Handling", EditorStyles.boldLabel);
            skipGroundPlanes = EditorGUILayout.ToggleLeft(
                new GUIContent("⛔ Skip Ground Planes Under Buildings", 
                    "Exclude flat planes below buildings from getting colliders. " +
                    "Terrain collider is sufficient — extra ground planes create invisible walls that break camera."),
                skipGroundPlanes);
            
            GUILayout.Space(5);
            EditorGUILayout.LabelField("Size Filter", EditorStyles.boldLabel);
            minimumObjectSize = EditorGUILayout.Slider(
                new GUIContent("Minimum Object Size (m)", "Objects smaller than this in ALL dimensions are skipped. Prevents colliders on tiny decorations."),
                minimumObjectSize, 0.1f, 3f);
            
            GUILayout.Space(5);
            EditorGUILayout.LabelField("Generation Options", EditorStyles.boldLabel);
            optimizeForPerformance = EditorGUILayout.ToggleLeft(
                new GUIContent("Optimize for Performance", "Use simplified meshes and batch colliders"),
                optimizeForPerformance);
            
            createCompoundForComplex = EditorGUILayout.ToggleLeft(
                new GUIContent("Compound Colliders for Complex Objects", "Create multiple BoxColliders for complex buildings"),
                createCompoundForComplex);
            
            removeExistingFirst = EditorGUILayout.ToggleLeft(
                new GUIContent("Remove Existing Colliders First", "Clear all existing colliders before generation"),
                removeExistingFirst);
            
            EditorGUILayout.EndVertical();
            GUILayout.Space(8);
        }
        
        private void DrawAdvancedSettings()
        {
            showAdvancedSettings = EditorGUILayout.Foldout(showAdvancedSettings, "🔬 Advanced Settings", true);
            
            if (showAdvancedSettings)
            {
                EditorGUILayout.BeginVertical("box");
                
                // OBB and Structure Following
                EditorGUILayout.LabelField("Structure Following", EditorStyles.boldLabel);
                useOBBFitting = EditorGUILayout.ToggleLeft(
                    new GUIContent("Use OBB Fitting", "Use Oriented Bounding Boxes instead of AABB for better structure following"),
                    useOBBFitting);
                detectArchitecturalFeatures = EditorGUILayout.ToggleLeft(
                    new GUIContent("Detect Architectural Features", "Identify walls, floors, roofs separately"),
                    detectArchitecturalFeatures);
                
                GUILayout.Space(5);
                
                // Gap Prevention
                EditorGUILayout.LabelField("Gap Prevention", EditorStyles.boldLabel);
                fillGaps = EditorGUILayout.ToggleLeft(
                    new GUIContent("Fill Collision Gaps", "Detect and fill gaps in collision coverage"),
                    fillGaps);
                colliderOverlap = EditorGUILayout.Slider(
                    new GUIContent("Collider Overlap", "Overlap amount at edges to prevent gaps (meters)"),
                    colliderOverlap, 0f, 0.1f);
                gapDetectionSpacing = EditorGUILayout.Slider(
                    new GUIContent("Gap Detection Spacing", "Ray spacing for gap detection (meters)"),
                    gapDetectionSpacing, 0.1f, 2f);
                
                GUILayout.Space(5);
                
                // Complexity Thresholds
                EditorGUILayout.LabelField("Complexity Thresholds", EditorStyles.boldLabel);
                complexityThreshold = EditorGUILayout.IntSlider(
                    new GUIContent("Child Renderer Threshold", "Objects with more renderers are treated as complex"),
                    complexityThreshold, 2, 50);
                vertexThreshold = EditorGUILayout.IntSlider(
                    new GUIContent("Vertex Threshold", "Objects exceeding this are treated as complex"),
                    vertexThreshold, 500, 20000);
                
                GUILayout.Space(5);
                
                // Triangle Limits
                EditorGUILayout.LabelField("Triangle Limits (per collider)", EditorStyles.boldLabel);
                maxTrianglesLow = EditorGUILayout.IntField("Low Detail Max", maxTrianglesLow);
                maxTrianglesMedium = EditorGUILayout.IntField("Medium Detail Max", maxTrianglesMedium);
                maxTrianglesHigh = EditorGUILayout.IntField("High Detail Max", maxTrianglesHigh);
                
                GUILayout.Space(5);
                
                // Performance
                EditorGUILayout.LabelField("Performance", EditorStyles.boldLabel);
                markAsStatic = EditorGUILayout.ToggleLeft("Mark Environment as Static", markAsStatic);
                bakeMeshColliders = EditorGUILayout.ToggleLeft("Pre-bake Mesh Colliders", bakeMeshColliders);
                
                GUILayout.Space(5);
                
                // Ground Layer
                EditorGUILayout.LabelField("Ground Configuration", EditorStyles.boldLabel);
                groundLayer = EditorGUILayout.LayerField("Ground Layer", groundLayer);
                
                EditorGUILayout.EndVertical();
            }
            
            GUILayout.Space(8);
        }
        
        private void DrawActionButtons()
        {
            EditorGUILayout.BeginVertical("box");
            
            GUI.enabled = !isProcessing && environmentParent != null;
            
            EditorGUILayout.BeginHorizontal();
            
            if (GUILayout.Button("🔍 Analyze Environment", GUILayout.Height(35)))
            {
                AnalyzeEnvironmentAsync();
            }
            
            if (GUILayout.Button("🧹 Clear Analysis", GUILayout.Height(35)))
            {
                ClearAnalysis();
            }
            
            EditorGUILayout.EndHorizontal();
            
            GUILayout.Space(5);
            
            GUI.enabled = !isProcessing && analysisResults.Count > 0;
            
            var generateRect = EditorGUILayout.GetControlRect(false, 40);
            EditorGUI.DrawRect(generateRect, new Color(0.2f, 0.6f, 0.3f, 0.8f));
            if (GUI.Button(generateRect, "✅ Generate Colliders"))
            {
                GenerateCollidersAsync();
            }
            
            GUILayout.Space(5);
            
            EditorGUILayout.BeginHorizontal();
            
            GUI.enabled = !isProcessing && changeRecords.Count > 0;
            if (GUILayout.Button("↩️ Undo All Changes", GUILayout.Height(30)))
            {
                UndoAllChanges();
            }
            
            GUI.enabled = !isProcessing;
            if (GUILayout.Button("💾 Save Scene", GUILayout.Height(30)))
            {
                SaveScene();
            }
            
            EditorGUILayout.EndHorizontal();
            
            GUI.enabled = true;
            
            EditorGUILayout.EndVertical();
            GUILayout.Space(8);
        }
        
        private void DrawProgressBar()
        {
            EditorGUILayout.BeginVertical("box");
            
            EditorGUILayout.LabelField(statusMessage, EditorStyles.boldLabel);
            
            var progressRect = EditorGUILayout.GetControlRect(false, 20);
            EditorGUI.DrawRect(progressRect, new Color(0.1f, 0.1f, 0.1f, 0.8f));
            var fillRect = new Rect(progressRect.x + 2, progressRect.y + 2, 
                (progressRect.width - 4) * progress, progressRect.height - 4);
            EditorGUI.DrawRect(fillRect, new Color(0.3f, 0.7f, 0.4f, 0.9f));
            GUI.Label(progressRect, $"{(progress * 100):F0}%", 
                new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter });
            
            EditorGUILayout.EndVertical();
            GUILayout.Space(8);
        }
        
        private void DrawAnalysisResults()
        {
            EditorGUILayout.BeginVertical("box");
            GUILayout.Label($"📊 Analysis Results ({analysisResults.Count} objects)", sectionStyle);
            GUILayout.Space(5);
            
            // Quick select buttons
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Select All", GUILayout.Width(100)))
            {
                foreach (var r in analysisResults) r.selected = true;
            }
            if (GUILayout.Button("Select None", GUILayout.Width(100)))
            {
                foreach (var r in analysisResults) r.selected = false;
            }
            if (GUILayout.Button("Buildings Only", GUILayout.Width(100)))
            {
                foreach (var r in analysisResults) 
                    r.selected = r.objectType == "Building";
            }
            if (GUILayout.Button("Ground Only", GUILayout.Width(100)))
            {
                foreach (var r in analysisResults) 
                    r.selected = r.objectType == "Ground";
            }
            EditorGUILayout.EndHorizontal();
            
            GUILayout.Space(5);
            
            // Show first 50 results with pagination would be added here
            int displayCount = Mathf.Min(analysisResults.Count, 30);
            for (int i = 0; i < displayCount; i++)
            {
                var result = analysisResults[i];
                DrawAnalysisResultRow(result);
            }
            
            if (analysisResults.Count > displayCount)
            {
                EditorGUILayout.LabelField($"... and {analysisResults.Count - displayCount} more objects", 
                    EditorStyles.miniLabel);
            }
            
            EditorGUILayout.EndVertical();
            GUILayout.Space(8);
        }
        
        private void DrawAnalysisResultRow(AnalysisResult result)
        {
            EditorGUILayout.BeginHorizontal("box");
            
            // Color indicator
            var colorRect = EditorGUILayout.GetControlRect(GUILayout.Width(8), GUILayout.Height(18));
            EditorGUI.DrawRect(colorRect, result.displayColor);
            
            // Selection toggle
            result.selected = EditorGUILayout.Toggle(result.selected, GUILayout.Width(20));
            
            // Object name (clickable)
            if (GUILayout.Button(result.gameObject.name, EditorStyles.linkLabel, GUILayout.Width(180)))
            {
                Selection.activeGameObject = result.gameObject;
                EditorGUIUtility.PingObject(result.gameObject);
            }
            
            // Type
            GUILayout.Label(result.objectType, GUILayout.Width(70));
            
            // Recommended collider
            GUILayout.Label(result.recommendedCollider, GUILayout.Width(100));
            
            // Triangle count
            GUILayout.Label($"{result.triangleCount} tris", EditorStyles.miniLabel, GUILayout.Width(60));
            
            EditorGUILayout.EndHorizontal();
        }
        
        private void DrawStatistics()
        {
            EditorGUILayout.BeginVertical("box");
            GUILayout.Label("📈 Statistics", sectionStyle);
            GUILayout.Space(5);
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.BeginVertical();
            EditorGUILayout.LabelField($"Total Objects: {statistics.totalObjects}");
            EditorGUILayout.LabelField($"With Colliders: {statistics.objectsWithColliders}");
            EditorGUILayout.LabelField($"Need Colliders: {statistics.objectsNeedingColliders}");
            EditorGUILayout.EndVertical();
            
            EditorGUILayout.BeginVertical();
            EditorGUILayout.LabelField($"Buildings: {statistics.buildingCount}");
            EditorGUILayout.LabelField($"Ground: {statistics.groundCount}");
            EditorGUILayout.LabelField($"Props: {statistics.propCount}");
            EditorGUILayout.EndVertical();
            
            EditorGUILayout.BeginVertical();
            EditorGUILayout.LabelField($"Original Mesh: {FormatBytes(statistics.originalMeshMemoryBytes)}");
            EditorGUILayout.LabelField($"Collision Est: {FormatBytes(statistics.estimatedMemoryBytes)}");
            EditorGUILayout.LabelField($"Triangles: {statistics.totalTriangles} → {statistics.optimizedTriangles}");
            EditorGUILayout.EndVertical();
            EditorGUILayout.EndHorizontal();
            
            // Memory warning
            if (statistics.estimatedMemoryBytes > 50 * 1024 * 1024) // 50MB
            {
                EditorGUILayout.HelpBox(
                    $"Estimated collision memory ({FormatBytes(statistics.estimatedMemoryBytes)}) exceeds 50MB. " +
                    "Consider using lower detail level or more compound colliders.", 
                    MessageType.Warning);
            }
            
            EditorGUILayout.EndVertical();
            GUILayout.Space(8);
        }
        
        private void DrawLogSection()
        {
            if (logMessages.Count == 0) return;
            
            EditorGUILayout.BeginVertical("box");
            
            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("📝 Log", sectionStyle);
            if (GUILayout.Button("Clear", GUILayout.Width(50)))
            {
                logMessages.Clear();
            }
            EditorGUILayout.EndHorizontal();
            
            GUILayout.Space(5);
            
            // Show last 10 messages
            int start = Mathf.Max(0, logMessages.Count - 10);
            for (int i = start; i < logMessages.Count; i++)
            {
                EditorGUILayout.LabelField(logMessages[i], logStyle);
            }
            
            EditorGUILayout.EndVertical();
        }
        
        #endregion
        
        #region Analysis
        
        private async void AnalyzeEnvironmentAsync()
        {
            if (environmentParent == null) return;
            
            isProcessing = true;
            progress = 0f;
            statusMessage = "Analyzing environment...";
            analysisResults.Clear();
            statistics.Reset();
            logMessages.Clear();
            
            Log("Starting environment analysis...");
            
            try
            {
                // ===== NEW APPROACH: Find TOP-LEVEL structural objects =====
                // Instead of iterating every renderer (21000+), walk the hierarchy
                // and find meaningful parent objects (buildings, ground, props).
                // Each top-level object gets ONE collider covering all its children.
                
                var processedObjects = new HashSet<GameObject>(); // Track what we've already handled
                var topLevelObjects = FindTopLevelStructuralObjects(environmentParent, processedObjects);
                
                float total = Mathf.Max(1, topLevelObjects.Count);
                int processed = 0;
                
                statistics.totalObjects = topLevelObjects.Count;
                
                foreach (var obj in topLevelObjects)
                {
                    if (obj == null) continue;
                    
                    var result = AnalyzeTopLevelObject(obj);
                    if (result != null)
                    {
                        // === FILTER BY CATEGORY during analysis ===
                        // Only add results for categories the user has enabled
                        bool include = true;
                        if (result.objectType == "Building" && !generateForBuildings) include = false;
                        if (result.objectType == "Ground" && !generateForGround) include = false;
                        if (result.objectType == "Prop" && !generateForProps) include = false;
                        if (result.objectType == "Vegetation" && !generateForVegetation) include = false;
                        
                        if (include)
                        {
                            analysisResults.Add(result);
                        }
                    }
                    
                    processed++;
                    progress = processed / total;
                    statusMessage = $"Analyzing: {obj.name}";
                    
                    if (processed % 50 == 0)
                    {
                        Repaint();
                        await Task.Yield();
                    }
                }
                
                // Analyze ground/terrain separately
                if (groundTerrain != null && generateForGround)
                {
                    var groundResult = AnalyzeGroundObject(groundTerrain);
                    if (groundResult != null)
                    {
                        analysisResults.Insert(0, groundResult);
                    }
                }
                
                // Calculate statistics
                CalculateStatistics();
                
                Log($"Analysis complete: {analysisResults.Count} objects analyzed (from {statistics.totalObjects} top-level objects)");
                Log($"Buildings: {statistics.buildingCount}, Ground: {statistics.groundCount}, Props: {statistics.propCount}");
                Log($"Skipped {statistics.vegetationCount} vegetation, filtered {statistics.totalObjects - analysisResults.Count} objects below min size");
                
                statusMessage = "Analysis complete!";
                progress = 1f;
            }
            catch (System.Exception e)
            {
                Log($"<color=red>Error: {e.Message}</color>");
                statusMessage = "Analysis failed!";
            }
            finally
            {
                isProcessing = false;
                Repaint();
            }
        }
        
        /// <summary>
        /// Find top-level structural objects in the hierarchy.
        /// A "top-level" object is one whose PARENT is the environment root (or 1-2 levels deep),
        /// and it has renderers (itself or children). We treat each as ONE collider target.
        /// This dramatically reduces collider count vs iterating every renderer.
        /// </summary>
        private List<GameObject> FindTopLevelStructuralObjects(GameObject root, HashSet<GameObject> processed)
        {
            var results = new List<GameObject>();
            
            // Walk direct children of environment parent
            foreach (Transform child in root.transform)
            {
                if (child == null || !child.gameObject.activeInHierarchy) continue;
                if (processed.Contains(child.gameObject)) continue;
                
                // Check if this child has any renderers (itself or descendants)
                var childRenderers = child.GetComponentsInChildren<Renderer>(true);
                if (childRenderers.Length == 0) continue;
                
                // Calculate combined bounds of all child renderers
                Bounds combinedBounds = childRenderers[0].bounds;
                for (int i = 1; i < childRenderers.Length; i++)
                {
                    if (childRenderers[i] != null)
                        combinedBounds.Encapsulate(childRenderers[i].bounds);
                }
                
                Vector3 size = combinedBounds.size;
                
                // If this is a large container with many sub-buildings,
                // go one level deeper to find individual buildings
                bool isLargeContainer = (size.x > 50f || size.z > 50f) && child.childCount > 5;
                
                if (isLargeContainer)
                {
                    // This is probably a "Buildings" or "Props" container folder.
                    // Go one level deeper to find individual buildings.
                    foreach (Transform grandchild in child)
                    {
                        if (grandchild == null || !grandchild.gameObject.activeInHierarchy) continue;
                        if (processed.Contains(grandchild.gameObject)) continue;
                        
                        var gcRenderers = grandchild.GetComponentsInChildren<Renderer>(true);
                        if (gcRenderers.Length == 0) continue;
                        
                        processed.Add(grandchild.gameObject);
                        results.Add(grandchild.gameObject);
                    }
                }
                else
                {
                    processed.Add(child.gameObject);
                    results.Add(child.gameObject);
                }
            }
            
            return results;
        }
        
        /// <summary>
        /// Analyze a top-level object (building, prop, or ground piece).
        /// Uses combined bounds of ALL child renderers for a single collider.
        /// </summary>
        private AnalysisResult AnalyzeTopLevelObject(GameObject obj)
        {
            if (obj == null) return null;
            if (!obj.activeInHierarchy) return null;
            
            // Get combined bounds from ALL child renderers
            var renderers = obj.GetComponentsInChildren<Renderer>(true);
            if (renderers.Length == 0) return null;
            
            Bounds combinedBounds = renderers[0].bounds;
            int totalVerts = 0;
            int totalTris = 0;
            
            foreach (var r in renderers)
            {
                if (r == null) continue;
                combinedBounds.Encapsulate(r.bounds);
                
                var mf = r.GetComponent<MeshFilter>();
                if (mf != null && mf.sharedMesh != null)
                {
                    totalVerts += mf.sharedMesh.vertexCount;
                    if (mf.sharedMesh.isReadable)
                        totalTris += mf.sharedMesh.triangles.Length / 3;
                }
            }
            
            Vector3 size = combinedBounds.size;
            string name = obj.name.ToLower();
            Mesh mesh = GetMeshFromObject(obj); // Root mesh (may be null for parent containers)
            
            // === SIZE FILTER: Skip objects too small to matter ===
            // Per Unity docs: fewer colliders = better performance
            if (size.x < minimumObjectSize && size.y < minimumObjectSize && size.z < minimumObjectSize)
            {
                return null; // Too small, skip entirely
            }
            
            var result = new AnalysisResult
            {
                gameObject = obj,
                vertexCount = totalVerts,
                triangleCount = totalTris,
                bounds = size
            };
            
            // === CLASSIFY ===
            ClassifyTopLevelObject(obj, name, size, renderers.Length, mesh, result);
            
            // Set display color
            result.displayColor = GetColorForColliderType(result.recommendedCollider);
            
            return result;
        }
        
        private AnalysisResult AnalyzeGroundObject(GameObject obj)
        {
            if (obj == null) return null;
            
            var terrain = obj.GetComponent<Terrain>();
            var terrainCollider = obj.GetComponent<TerrainCollider>();
            
            var result = new AnalysisResult
            {
                gameObject = obj,
                objectType = "Ground",
                displayColor = new Color(0.6f, 0.4f, 0.2f, 0.8f)
            };
            
            if (terrain != null)
            {
                result.recommendedCollider = "TerrainCollider";
                result.reason = terrainCollider != null ? 
                    "Terrain already has TerrainCollider" : 
                    "Unity Terrain - needs TerrainCollider";
                result.bounds = terrain.terrainData != null ? terrain.terrainData.size : Vector3.zero;
                statistics.groundCount++;
            }
            else
            {
                Mesh mesh = GetMeshFromObject(obj);
                if (mesh != null)
                {
                    result.recommendedCollider = "MeshCollider";
                    result.reason = "Mesh-based ground";
                    result.vertexCount = mesh.vertexCount;
                    result.triangleCount = mesh.isReadable ? mesh.triangles.Length / 3 : 0;
                    var renderer = obj.GetComponent<Renderer>();
                    result.bounds = renderer != null ? renderer.bounds.size : Vector3.zero;
                    statistics.groundCount++;
                }
            }
            
            return result;
        }
        
        /// <summary>
        /// Classify a top-level structural object. 
        /// KEY PRINCIPLE (from Unity docs): 
        ///   Sphere > Capsule > Box > Convex Mesh > Non-convex Mesh (performance order)
        ///   ONE collider per building is ideal. Fewer colliders = better mobile performance.
        /// </summary>
        private void ClassifyTopLevelObject(GameObject obj, string name, Vector3 size, int rendererCount, Mesh rootMesh, AnalysisResult result)
        {
            // === VEGETATION: Skip entirely ===
            if (IsVegetation(obj, name, size, rootMesh))
            {
                result.objectType = "Vegetation";
                result.recommendedCollider = "Skip";
                result.reason = "Vegetation - no collider needed";
                result.displayColor = new Color(0.3f, 0.8f, 0.3f, 0.5f);
                result.selected = false;
                statistics.vegetationCount++;
                return;
            }
            
            // === GROUND: Check BEFORE buildings ===
            // But skip ground planes if they're under buildings or if skipGroundPlanes is enabled
            if (IsGround(obj, name, size, rootMesh))
            {
                // If skipGroundPlanes is enabled, skip ALL ground/plane objects
                // because the terrain collider already handles ground collision.
                // These extra planes create invisible walls that break the camera.
                if (skipGroundPlanes)
                {
                    result.objectType = "Ground";
                    result.recommendedCollider = "Skip";
                    result.reason = "Ground plane skipped (terrain collider is sufficient)";
                    result.displayColor = new Color(0.6f, 0.4f, 0.2f, 0.3f);
                    result.selected = false;
                    statistics.groundCount++;
                    return;
                }
                
                result.objectType = "Ground";
                result.recommendedCollider = "MeshCollider";
                result.reason = "Ground surface - non-convex for accuracy";
                statistics.groundCount++;
                return;
            }
            
            // === BUILDING: ONE collider for the whole building ===
            if (IsBuilding(obj, name, size))
            {
                result.objectType = "Building";
                statistics.buildingCount++;
                
                // Per Unity docs: prefer BoxCollider (efficient)
                // ONE BoxCollider per building wrapping all children = simple and fast
                result.recommendedCollider = "BoxCollider";
                result.reason = $"Single BoxCollider for entire building ({rendererCount} parts)";
                return;
            }
            
            // === PROP: Usually BoxCollider is fine ===
            result.objectType = "Prop";
            statistics.propCount++;
            result.recommendedCollider = "BoxCollider";
            result.reason = $"BoxCollider for prop ({rendererCount} parts)";
        }
        

        
        private void CalculateStatistics()
        {
            statistics.totalTriangles = 0;
            statistics.optimizedTriangles = 0;
            statistics.originalMeshMemoryBytes = 0;
            statistics.estimatedMemoryBytes = 0;
            
            int maxTris = GetMaxTrianglesForDetailLevel();
            
            foreach (var result in analysisResults)
            {
                if (result.recommendedCollider == "Skip") continue;
                
                statistics.totalTriangles += result.triangleCount;
                
                // Estimate optimized triangle count
                int optimized = result.recommendedCollider switch
                {
                    "BoxCollider" => 12,
                    "ConvexMesh" => Mathf.Min(result.triangleCount, 255),
                    "MeshCollider" => Mathf.Min(result.triangleCount, maxTris),
                    _ => result.triangleCount
                };
                statistics.optimizedTriangles += optimized;
                
                // Estimate memory (rough: ~12 bytes per vertex, ~4 bytes per triangle index)
                statistics.originalMeshMemoryBytes += (result.vertexCount * 12) + (result.triangleCount * 12);
                
                // Collision mesh memory estimate
                int collisionVerts = result.recommendedCollider switch
                {
                    "BoxCollider" => 8,
                    "ConvexMesh" => Mathf.Min(result.vertexCount, 255),
                    "MeshCollider" => Mathf.Min(result.vertexCount, maxTris * 3),
                    _ => Mathf.Min(result.vertexCount, maxTris * 3)
                };
                statistics.estimatedMemoryBytes += collisionVerts * 12 + optimized * 12;
            }
        }
        
        private int GetMaxTrianglesForDetailLevel()
        {
            return detailLevel switch
            {
                DetailLevel.Low => maxTrianglesLow,
                DetailLevel.Medium => maxTrianglesMedium,
                DetailLevel.High => maxTrianglesHigh,
                _ => maxTrianglesMedium
            };
        }
        
        #endregion
        
        #region Classification Helpers
        
        private bool IsVegetation(GameObject obj, string name, Vector3 size, Mesh mesh)
        {
            // Name-based detection
            string[] vegetationKeywords = { "tree", "grass", "plant", "bush", "shrub", "flower", 
                "leaf", "foliage", "fern", "vine", "hedge", "weed" };
            
            foreach (var keyword in vegetationKeywords)
            {
                if (name.Contains(keyword)) return true;
                if (NameOrAncestorContains(obj, keyword)) return true;
            }
            
            // Small ground cover
            if (size.y < 0.6f && size.x < 0.8f && size.z < 0.8f)
            {
                if (mesh != null && mesh.vertexCount < 200) return true;
            }
            
            return false;
        }
        
        private bool IsBuilding(GameObject obj, string name, Vector3 size)
        {
            // Name-based
            string[] buildingKeywords = { "building", "house", "wall", "structure", "apartment", 
                "shop", "store", "tower", "bridge", "fence", "gate" };
            
            foreach (var keyword in buildingKeywords)
            {
                if (name.Contains(keyword)) return true;
            }
            
            // Size-based: Large structures
            if (size.x > 5f || size.y > 3f || size.z > 5f)
            {
                return true;
            }
            
            // Wall-like: long and tall
            if ((size.x > size.z * 3f || size.z > size.x * 3f) && size.y > 1.5f)
            {
                return true;
            }
            
            return false;
        }
        
        private bool IsGround(GameObject obj, string name, Vector3 size, Mesh mesh)
        {
            // Name-based
            string[] groundKeywords = { "ground", "floor", "terrain", "surface", "plane", "platform" };
            
            foreach (var keyword in groundKeywords)
            {
                if (name.Contains(keyword)) return true;
            }
            
            // Very flat and wide — CLASSIC ground plane detection
            // This catches planes placed under buildings that create invisible walls
            if (size.y < Mathf.Min(size.x, size.z) * 0.1f && (size.x > 3f || size.z > 3f))
            {
                return true;
            }
            
            // Check mesh flatness (nearly zero height = plane)
            if (mesh != null && mesh.bounds.size.y < 0.01f)
            {
                return true;
            }
            
            // Detect Unity default Plane mesh (10x10 quad with y=0)
            if (mesh != null && mesh.vertexCount <= 121 && size.y < 0.05f)
            {
                return true;
            }
            
            return false;
        }
        

        
        private bool NameOrAncestorContains(GameObject obj, string keyword)
        {
            Transform t = obj.transform;
            while (t != null)
            {
                if (t.name.ToLower().Contains(keyword))
                    return true;
                t = t.parent;
            }
            return false;
        }
        
        private Mesh GetMeshFromObject(GameObject obj)
        {
            var mf = obj.GetComponent<MeshFilter>();
            if (mf != null && mf.sharedMesh != null) return mf.sharedMesh;
            
            var smr = obj.GetComponent<SkinnedMeshRenderer>();
            if (smr != null && smr.sharedMesh != null) return smr.sharedMesh;
            
            return null;
        }
        
        private Color GetColorForColliderType(string type)
        {
            return type switch
            {
                "BoxCollider" => new Color(0.2f, 0.8f, 0.2f, 0.8f),
                "ConvexMesh" => new Color(0.2f, 0.6f, 0.9f, 0.8f),
                "MeshCollider" => new Color(0.9f, 0.5f, 0.2f, 0.8f),
                "TerrainCollider" => new Color(0.6f, 0.4f, 0.2f, 0.8f),
                "Skip" => new Color(0.5f, 0.5f, 0.5f, 0.4f),
                _ => Color.white
            };
        }
        
        #endregion
        
        #region Utility
        
        private void ClearAnalysis()
        {
            analysisResults.Clear();
            statistics.Reset();
            logMessages.Clear();
            progress = 0f;
            statusMessage = "";
            Repaint();
        }
        
        private void Log(string message)
        {
            logMessages.Add($"[{System.DateTime.Now:HH:mm:ss}] {message}");
            Debug.Log($"[OptimizedColliderTool] {message}");
        }
        
        private string FormatBytes(long bytes)
        {
            if (bytes < 1024) return $"{bytes} B";
            if (bytes < 1024 * 1024) return $"{bytes / 1024f:F1} KB";
            return $"{bytes / (1024f * 1024f):F1} MB";
        }
        
        /// <summary>
        /// Bake all MeshColliders under a parent for runtime performance
        /// </summary>
        private void BakeMeshCollidersInline(GameObject parent)
        {
            var meshColliders = parent.GetComponentsInChildren<MeshCollider>(true);
            foreach (var mc in meshColliders)
            {
                if (mc != null && mc.sharedMesh != null)
                {
                    Physics.BakeMesh(mc.sharedMesh.GetInstanceID(), mc.convex);
                }
            }
        }
        
        /// <summary>
        /// Add a non-convex MeshCollider for ground surfaces
        /// </summary>
        private Collider AddGroundMeshColliderInline(GameObject obj, Mesh mesh)
        {
            if (obj == null) return null;
            if (obj.GetComponent<Collider>() != null) return null;
            
            var mc = Undo.AddComponent<MeshCollider>(obj);
            if (mesh != null) mc.sharedMesh = mesh;
            mc.convex = false;
            
            // Set cooking options for readable meshes
            if (mesh != null && mesh.isReadable)
            {
                mc.cookingOptions = MeshColliderCookingOptions.CookForFasterSimulation |
                                   MeshColliderCookingOptions.EnableMeshCleaning |
                                   MeshColliderCookingOptions.WeldColocatedVertices;
            }
            
            return mc;
        }
        
        /// <summary>
        /// Add a convex MeshCollider for props
        /// </summary>
        private Collider AddConvexMeshColliderInline(GameObject obj, Mesh mesh)
        {
            if (obj == null) return null;
            if (obj.GetComponent<Collider>() != null) return null;
            
            var mc = Undo.AddComponent<MeshCollider>(obj);
            if (mesh != null) mc.sharedMesh = mesh;
            mc.convex = true;
            
            return mc;
        }
        
        private void SaveScene()
        {
            var scene = SceneManager.GetActiveScene();
            if (scene.isDirty)
            {
                EditorSceneManager.SaveScene(scene);
                Log($"Scene '{scene.name}' saved.");
            }
        }
        
        private void UndoAllChanges()
        {
            if (changeRecords.Count == 0) return;
            
            if (!EditorUtility.DisplayDialog("Undo Changes", 
                $"Revert {changeRecords.Count} collider changes?", "Undo", "Cancel"))
                return;
            
            foreach (var record in changeRecords)
            {
                if (record.target == null) continue;
                
                if (record.addedCollider != null)
                {
                    Undo.DestroyObjectImmediate(record.addedCollider);
                }
                
                if (record.addedChild != null)
                {
                    Undo.DestroyObjectImmediate(record.addedChild);
                }
                
                if (record.flagsChanged)
                {
                    GameObjectUtility.SetStaticEditorFlags(record.target, record.previousFlags);
                }
            }
            
            changeRecords.Clear();
            Log("All changes undone.");
            Repaint();
        }
        
        #endregion
        
        #region Collider Generation - Full Implementation
        
        private async void GenerateCollidersAsync()
        {
            Log("Collider generation starting...");
            isProcessing = true;
            statusMessage = "Generating colliders...";
            
            try
            {
                var selectedResults = analysisResults.Where(r => r.selected && r.recommendedCollider != "Skip"
                    && (r.objectType != "Building" || generateForBuildings)
                    && (r.objectType != "Ground" || generateForGround)
                    && (r.objectType != "Prop" || generateForProps)
                    && (r.objectType != "Vegetation" || generateForVegetation)
                ).ToList();
                float total = Mathf.Max(1, selectedResults.Count);
                int processed = 0;
                
                if (removeExistingFirst)
                {
                    await RemoveExistingCollidersAsync();
                }
                
                foreach (var result in selectedResults)
                {
                    // Guard against destroyed objects (e.g. children of removed containers)
                    if (result.gameObject == null) { processed++; continue; }
                    
                    await GenerateColliderForObject(result);
                    
                    processed++;
                    progress = processed / total;
                    
                    // Safe name access after potential destruction
                    string objName = result.gameObject != null ? result.gameObject.name : "(destroyed)";
                    statusMessage = $"Generating: {objName}";
                    
                    if (processed % 20 == 0)
                    {
                        Repaint();
                        await Task.Yield();
                    }
                }
                
                // Fill gaps if enabled
                if (fillGaps && environmentParent != null)
                {
                    await DetectAndFillGapsAsync();
                }
                
                // Bake all mesh colliders for runtime performance
                if (bakeMeshColliders && environmentParent != null)
                {
                    BakeMeshCollidersInline(environmentParent);
                    Log("Baked all mesh colliders for runtime performance.");
                }
                
                Log($"Generated colliders for {processed} objects.");
                statusMessage = "Generation complete!";
                progress = 1f;
            }
            catch (System.Exception e)
            {
                Log($"<color=red>Error: {e.Message}</color>");
                Debug.LogError($"Collider generation error: {e}");
                statusMessage = "Generation failed!";
            }
            finally
            {
                isProcessing = false;
                Repaint();
            }
        }
        
        private async Task RemoveExistingCollidersAsync()
        {
            Log("Removing existing colliders...");
            
            var colliders = environmentParent.GetComponentsInChildren<Collider>(true);
            int removed = 0;
            foreach (var col in colliders)
            {
                if (col == null) continue; // Already destroyed
                if (col is TerrainCollider) continue; // Keep terrain colliders
                Undo.DestroyObjectImmediate(col);
                removed++;
            }
            
            // Collect all "Colliders" containers FIRST, then destroy
            // (destroying a parent invalidates child transforms still in the iteration array)
            var containersToDestroy = new List<GameObject>();
            foreach (Transform child in environmentParent.GetComponentsInChildren<Transform>(true))
            {
                if (child == null) continue;
                if (child.name == "Colliders" && child.parent != null)
                {
                    containersToDestroy.Add(child.gameObject);
                }
            }
            // Also collect OBB child collider objects from previous runs
            foreach (Transform child in environmentParent.GetComponentsInChildren<Transform>(true))
            {
                if (child == null) continue;
                if (child.name.StartsWith("BoxCollider_OBB") || child.name == "CompoundColliders")
                {
                    if (!containersToDestroy.Contains(child.gameObject))
                        containersToDestroy.Add(child.gameObject);
                }
            }
            
            foreach (var go in containersToDestroy)
            {
                if (go != null)
                {
                    Undo.DestroyObjectImmediate(go);
                    removed++;
                }
            }
            
            await Task.Yield();
            Log($"Removed {removed} existing colliders and containers.");
        }
        
        private async Task GenerateColliderForObject(AnalysisResult result)
        {
            GameObject obj = result.gameObject;
            if (obj == null) return;
            
            // For compound approach: check if this object OR its direct children already have colliders
            bool hasExistingColliders = obj.GetComponent<Collider>() != null;
            if (!hasExistingColliders)
            {
                foreach (Transform child in obj.transform)
                {
                    if (child != null && child.GetComponent<Collider>() != null)
                    {
                        hasExistingColliders = true;
                        break;
                    }
                }
            }
            if (hasExistingColliders) return;
            
            Undo.RecordObject(obj, "Add Collider");
            EditorUtility.SetDirty(obj);
            
            var prevFlags = GameObjectUtility.GetStaticEditorFlags(obj);
            
            Collider addedCollider = null;
            List<Collider> addedColliders = null;
            
            switch (result.recommendedCollider)
            {
                case "BoxCollider":
                    // === SINGLE BoxCollider per building (best practice for mobile) ===
                    // Per Unity docs: fewer colliders = better mobile performance
                    // ONE BoxCollider wrapping all children is simple, fast, and prevents
                    // the "3+ colliders per building" problem
                    if (createCompoundForComplex && result.objectType == "Building")
                    {
                        // Only use compound if user explicitly enabled it
                        addedColliders = AddCompoundChildColliders(obj);
                        addedCollider = addedColliders.Count > 0 ? addedColliders[0] : null;
                    }
                    else
                    {
                        // Default: ONE BoxCollider (simple + optimized)
                        addedCollider = AddLocalSpaceBoxCollider(obj);
                    }
                    break;
                    
                case "MeshCollider":
                    // Ground/terrain: use non-convex mesh for accurate surface
                    Mesh groundMesh = GetMeshFromObject(obj);
                    addedCollider = AddGroundMeshColliderInline(obj, groundMesh);
                    break;
                    
                case "TerrainCollider":
                    addedCollider = ConfigureTerrainCollider(obj);
                    break;
                    
                case "ConvexMesh":
                    Mesh convexMesh = GetMeshFromObject(obj);
                    addedCollider = AddConvexMeshColliderInline(obj, convexMesh);
                    if (addedCollider == null)
                    {
                        // Fallback to BoxCollider
                        addedCollider = AddLocalSpaceBoxCollider(obj);
                    }
                    break;
                    
                default:
                    // Default: safe BoxCollider
                    addedCollider = AddLocalSpaceBoxCollider(obj);
                    break;
            }
            
            // Mark as static if enabled (buildings and ground benefit from static batching)
            if (markAsStatic && addedCollider != null)
            {
                TryMarkStatic(obj);
            }
            
            // Record change for undo
            changeRecords.Add(new ColliderChangeRecord
            {
                target = obj,
                addedCollider = addedCollider,
                previousFlags = prevFlags,
                flagsChanged = prevFlags != GameObjectUtility.GetStaticEditorFlags(obj)
            });
            
            await Task.Yield();
        }
        
        /// <summary>
        /// COMPOUND COLLIDER APPROACH (Best practice per Unity docs):
        /// Place BoxColliders on the DIRECT CHILDREN of a building/prop.
        /// Each child's BoxCollider uses LOCAL bounds → naturally follows rotation.
        /// 
        /// This gives ~3-10 tight-fitting BoxColliders per building instead of
        /// 1 loose axis-aligned box. Per Unity docs:
        /// "Use compound colliders when a single primitive can't accurately represent the shape."
        /// </summary>
        private List<Collider> AddCompoundChildColliders(GameObject obj)
        {
            var addedColliders = new List<Collider>();
            if (obj == null) return addedColliders;
            
            // --- Step 1: If this object itself has a mesh, add a BoxCollider from mesh.bounds ---
            Mesh selfMesh = GetMeshFromObject(obj);
            if (selfMesh != null && obj.GetComponent<Collider>() == null)
            {
                BoxCollider selfBox = Undo.AddComponent<BoxCollider>(obj);
                selfBox.center = selfMesh.bounds.center;
                selfBox.size = selfMesh.bounds.size + Vector3.one * colliderOverlap;
                addedColliders.Add(selfBox);
            }
            
            // --- Step 2: Collect direct children that have renderers ---
            var childrenWithGeometry = new List<Transform>();
            foreach (Transform child in obj.transform)
            {
                if (child == null || !child.gameObject.activeInHierarchy) continue;
                
                // Check if this child or its descendants have any renderers
                var renderers = child.GetComponentsInChildren<Renderer>(true);
                if (renderers.Length == 0) continue;
                
                // Skip if child already has a collider
                if (child.GetComponent<Collider>() != null) continue;
                
                // Size filter: skip tiny parts (decorations, bolts, etc.)
                Bounds childBounds = renderers[0].bounds;
                for (int i = 1; i < renderers.Length; i++)
                {
                    if (renderers[i] != null)
                        childBounds.Encapsulate(renderers[i].bounds);
                }
                Vector3 size = childBounds.size;
                if (size.x < minimumObjectSize && size.y < minimumObjectSize && size.z < minimumObjectSize)
                    continue;
                
                childrenWithGeometry.Add(child);
            }
            
            // --- Step 3: If too many children, merge into groups ---
            // Per Unity docs: "Use as few primitive colliders as possible"
            if (childrenWithGeometry.Count > 15)
            {
                // Too many parts — fall back to a single proper local-space BoxCollider
                BoxCollider singleBox = AddLocalSpaceBoxCollider(obj);
                if (singleBox != null)
                    addedColliders.Add(singleBox);
                return addedColliders;
            }
            
            // If no direct children have geometry (leaf object), add single collider
            if (childrenWithGeometry.Count == 0 && selfMesh == null)
            {
                BoxCollider singleBox = AddLocalSpaceBoxCollider(obj);
                if (singleBox != null)
                    addedColliders.Add(singleBox);
                return addedColliders;
            }
            
            // --- Step 4: Add BoxCollider to each significant child ---
            foreach (Transform child in childrenWithGeometry)
            {
                // Check if child has its own MeshFilter → use mesh.bounds (PERFECT local fit)
                Mesh childMesh = GetMeshFromObject(child.gameObject);
                
                if (childMesh != null && child.GetComponentsInChildren<Renderer>(true).Length <= 1)
                {
                    // Single-mesh child: BoxCollider from mesh.bounds (ideal!)
                    BoxCollider box = Undo.AddComponent<BoxCollider>(child.gameObject);
                    box.center = childMesh.bounds.center;
                    box.size = childMesh.bounds.size + Vector3.one * colliderOverlap;
                    addedColliders.Add(box);
                }
                else
                {
                    // Container child with sub-renderers: compute local-space combined bounds
                    BoxCollider box = AddLocalSpaceBoxCollider(child.gameObject);
                    if (box != null)
                        addedColliders.Add(box);
                }
            }
            
            return addedColliders;
        }
        
        /// <summary>
        /// Compute a BoxCollider using PROPER local-space bounds.
        /// Unlike the old AABB approach, this converts world corners to local space,
        /// so the box follows the object's rotation accurately.
        /// </summary>
        private BoxCollider AddLocalSpaceBoxCollider(GameObject obj)
        {
            if (obj == null) return null;
            if (obj.GetComponent<Collider>() != null) return null;
            
            // First: if object has its own mesh, use mesh.bounds directly (perfect!)
            Mesh selfMesh = GetMeshFromObject(obj);
            if (selfMesh != null)
            {
                BoxCollider box = Undo.AddComponent<BoxCollider>(obj);
                box.center = selfMesh.bounds.center;
                box.size = selfMesh.bounds.size + Vector3.one * colliderOverlap;
                return box;
            }
            
            // Otherwise: combine child renderer bounds in LOCAL space
            var renderers = obj.GetComponentsInChildren<Renderer>(true);
            if (renderers.Length == 0) return null;
            
            Transform t = obj.transform;
            Vector3 localMin = Vector3.one * float.MaxValue;
            Vector3 localMax = Vector3.one * float.MinValue;
            
            foreach (var r in renderers)
            {
                if (r == null) continue;
                
                Bounds b = r.bounds; // World-space AABB
                Vector3 center = b.center;
                Vector3 extents = b.extents;
                
                // Convert all 8 corners of world AABB to local space
                // This is the KEY fix: local-space AABB follows object rotation
                for (int i = 0; i < 8; i++)
                {
                    Vector3 corner = center + new Vector3(
                        (i & 1) == 0 ? -extents.x : extents.x,
                        (i & 2) == 0 ? -extents.y : extents.y,
                        (i & 4) == 0 ? -extents.z : extents.z
                    );
                    
                    Vector3 localCorner = t.InverseTransformPoint(corner);
                    localMin = Vector3.Min(localMin, localCorner);
                    localMax = Vector3.Max(localMax, localCorner);
                }
            }
            
            Vector3 localCenter = (localMin + localMax) * 0.5f;
            Vector3 localSize = localMax - localMin;
            
            BoxCollider result = Undo.AddComponent<BoxCollider>(obj);
            result.center = localCenter;
            result.size = localSize + Vector3.one * colliderOverlap;
            
            return result;
        }
        
        private async Task DetectAndFillGapsAsync()
        {
            Log("Detecting collision gaps...");
            statusMessage = "Detecting gaps...";
            
            // Simplified gap detection via raycasting down from a grid
            if (environmentParent == null) return;
            
            var allRenderers = environmentParent.GetComponentsInChildren<Renderer>(true);
            if (allRenderers.Length == 0) return;
            
            Bounds envBounds = allRenderers[0].bounds;
            foreach (var r in allRenderers)
            {
                if (r != null) envBounds.Encapsulate(r.bounds);
            }
            
            int gapCount = 0;
            float checkHeight = envBounds.max.y + 5f;
            
            for (float x = envBounds.min.x; x <= envBounds.max.x; x += gapDetectionSpacing)
            {
                for (float z = envBounds.min.z; z <= envBounds.max.z; z += gapDetectionSpacing)
                {
                    Ray ray = new Ray(new Vector3(x, checkHeight, z), Vector3.down);
                    if (!Physics.Raycast(ray, checkHeight + 10f))
                    {
                        gapCount++;
                    }
                }
            }
            
            if (gapCount > 0)
            {
                Log($"Found {gapCount} potential gap points (no collision surface detected).");
            }
            else
            {
                Log("No gaps detected in collision coverage.");
            }
            
            await Task.Yield();
        }
        
        #endregion
        
        #region Collider Generation Methods
        
        /// <summary>
        /// Add an optimized BoxCollider with proper fitting
        /// </summary>
        private BoxCollider AddOptimizedBoxCollider(GameObject obj, Mesh mesh, bool useOBB)
        {
            if (obj.GetComponent<Collider>() != null) return null;
            
            var box = Undo.AddComponent<BoxCollider>(obj);
            
            if (mesh != null)
            {
                var bounds = mesh.bounds;
                box.center = bounds.center;
                box.size = bounds.size + Vector3.one * colliderOverlap;
            }
            else
            {
                // Fallback to renderer bounds
                var renderer = obj.GetComponent<Renderer>();
                if (renderer != null)
                {
                    var localCenter = obj.transform.InverseTransformPoint(renderer.bounds.center);
                    var localSize = renderer.bounds.size;
                    box.center = localCenter;
                    box.size = localSize + Vector3.one * colliderOverlap;
                }
            }
            
            return box;
        }
        
        /// <summary>
        /// Create advanced compound colliders using per-child or grouped approach
        /// </summary>
        private GameObject CreateAdvancedCompoundColliders(GameObject obj, Mesh mesh)
        {
            // Use existing compound collider approach
            var colliders = AddCompoundChildColliders(obj);
            if (colliders.Count > 0)
            {
                Log($"Created {colliders.Count} compound colliders for {obj.name}");
            }
            return null;
        }
        
        /// <summary>
        /// Add an optimized MeshCollider with optional simplification
        /// </summary>
        private MeshCollider AddOptimizedMeshCollider(GameObject obj, Mesh mesh, bool convex)
        {
            if (obj.GetComponent<Collider>() != null) return null;
            
            var mc = Undo.AddComponent<MeshCollider>(obj);
            
            if (mesh != null)
            {
                mc.sharedMesh = mesh;
            }
            
            mc.convex = convex;
            
            // CRITICAL: Only set explicit cooking options when mesh is readable.
            // Unity docs: non-default CookingOptions require isReadable=true.
            if (mesh != null && mesh.isReadable)
            {
                mc.cookingOptions = MeshColliderCookingOptions.CookForFasterSimulation |
                                   MeshColliderCookingOptions.EnableMeshCleaning |
                                   MeshColliderCookingOptions.WeldColocatedVertices;
                
                if (optimizeForPerformance)
                {
                    mc.cookingOptions |= MeshColliderCookingOptions.UseFastMidphase;
                }
            }
            
            return mc;
        }
        
        /// <summary>
        /// Configure TerrainCollider with optimal settings
        /// </summary>
        private Collider ConfigureTerrainCollider(GameObject obj)
        {
            // Inline terrain collider configuration
            var terrain = obj.GetComponent<Terrain>();
            var existingTC = obj.GetComponent<TerrainCollider>();
            
            if (terrain != null && existingTC == null)
            {
                var tc = Undo.AddComponent<TerrainCollider>(obj);
                tc.terrainData = terrain.terrainData;
            }
            else if (existingTC != null && terrain != null)
            {
                existingTC.terrainData = terrain.terrainData;
            }
            
            // Set layer
            obj.layer = groundLayer;
            
            // Enable tree colliders
            if (terrain != null)
            {
                terrain.treeDistance = 500f;
            }
            
            return obj.GetComponent<TerrainCollider>();
        }
        
        /// <summary>
        /// Mark object as static for batching and optimization
        /// </summary>
        private void TryMarkStatic(GameObject obj)
        {
            if (obj == null) return;
            
            // Skip dynamic objects
            if (obj.GetComponentInParent<Rigidbody>() != null) return;
            if (obj.GetComponentInParent<CharacterController>() != null) return;
            if (obj.GetComponentInParent<Animator>() != null)
            {
                string name = obj.name.ToLower();
                if (name.Contains("player") || name.Contains("enemy") || name.Contains("npc"))
                    return;
            }
            
            // Check tag
            string tag = obj.tag;
            if (tag == "Player" || tag == "Enemy" || tag == "Dynamic")
                return;
            
            var flags = StaticEditorFlags.BatchingStatic |
                       StaticEditorFlags.OccluderStatic |
                       StaticEditorFlags.OccludeeStatic |
                       StaticEditorFlags.ReflectionProbeStatic |
                       StaticEditorFlags.ContributeGI;
            
            var current = GameObjectUtility.GetStaticEditorFlags(obj);
            if ((current & flags) != flags)
            {
                GameObjectUtility.SetStaticEditorFlags(obj, current | flags);
            }
        }
        
        #endregion
        
        #region Scene View Visualization
        
        private void OnSceneGUI(SceneView sceneView)
        {
            if (analysisResults.Count == 0) return;
            
            foreach (var result in analysisResults)
            {
                if (!result.selected || result.gameObject == null) continue;
                
                // Simple, clean visualization - show colliders on this object AND children (compound)
                var collider = result.gameObject.GetComponent<Collider>();
                
                // Draw collider on the object itself
                DrawBoxColliderWireframe(collider as BoxCollider, new Color(0.2f, 0.9f, 0.2f, 0.8f));
                
                if (collider is MeshCollider)
                {
                    Handles.color = new Color(0.9f, 0.5f, 0.2f, 0.6f);
                    Handles.DrawWireCube(collider.bounds.center, collider.bounds.size);
                }
                
                // Draw compound child colliders (BoxColliders placed on direct children)
                foreach (Transform child in result.gameObject.transform)
                {
                    if (child == null) continue;
                    var childBox = child.GetComponent<BoxCollider>();
                    DrawBoxColliderWireframe(childBox, new Color(0.3f, 0.85f, 0.4f, 0.7f));
                }
                
                // Pre-generation preview (no colliders yet)
                if (collider == null && result.recommendedCollider != "Skip")
                {
                    // Check if any children have colliders (compound preview)
                    bool hasChildColliders = false;
                    foreach (Transform child in result.gameObject.transform)
                    {
                        if (child != null && child.GetComponent<Collider>() != null)
                        {
                            hasChildColliders = true;
                            break;
                        }
                    }
                    
                    if (!hasChildColliders)
                    {
                        // Show preview of where colliders would go
                        var renderers = result.gameObject.GetComponentsInChildren<Renderer>(true);
                        if (renderers.Length > 0)
                        {
                            Handles.color = new Color(0.5f, 0.5f, 1f, 0.3f);
                            Bounds combined = renderers[0].bounds;
                            for (int i = 1; i < renderers.Length; i++)
                            {
                                if (renderers[i] != null)
                                    combined.Encapsulate(renderers[i].bounds);
                            }
                            Handles.DrawWireCube(combined.center, combined.size);
                        }
                    }
                }
                // Skip drawing for vegetation/skipped objects
            }
        }
        
        /// <summary>
        /// Draw a rotation-aware wireframe for a BoxCollider
        /// </summary>
        private void DrawBoxColliderWireframe(BoxCollider boxCol, Color color)
        {
            if (boxCol == null) return;
            
            Handles.color = color;
            Transform t = boxCol.transform;
            Vector3 worldCenter = t.TransformPoint(boxCol.center);
            Matrix4x4 original = Handles.matrix;
            Handles.matrix = Matrix4x4.TRS(worldCenter, t.rotation, Vector3.one);
            Vector3 scaledSize = Vector3.Scale(boxCol.size, t.lossyScale);
            Handles.DrawWireCube(Vector3.zero, scaledSize);
            Handles.matrix = original;
        }
        
        private void OnFocus()
        {
            SceneView.duringSceneGui -= OnSceneGUI;
            SceneView.duringSceneGui += OnSceneGUI;
        }
        
        private void OnDestroy()
        {
            SceneView.duringSceneGui -= OnSceneGUI;
        }
        
        #endregion
    }
}
