using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.IO;
using System.Linq;
using System.Collections.Generic;

namespace AlterchaseSDK
{
    public class ModTesterWindow : EditorWindow
    {
        private string assetBundlePath = "";
        private string scenesBundlePath = "";
        private AssetBundle loadedBundle;
        private AssetBundle loadedScenesBundle;
        private ModPackage loadedPackage;
        private Vector2 scrollPosition;
        private bool isLoaded = false;
        private string testScenePath = "Assets/Scripts/AlterchaseSDK/TestScene.unity";
        private ModPackage selectedPackageForPath;
        
        private List<LevelModAsset> loadedLevels = new List<LevelModAsset>();
        private List<ModelModAsset> loadedModels = new List<ModelModAsset>();
        private List<EnemyModAsset> loadedEnemies = new List<EnemyModAsset>();

        [MenuItem("Alterchase SDK/Mod Tester", priority = 3)]
        public static void ShowWindow()
        {
            ModTesterWindow window = GetWindow<ModTesterWindow>("Mod Tester");
            window.minSize = new Vector2(400, 500);
            window.Show();
        }

        private void OnGUI()
        {
            EditorGUILayout.Space(10);
            EditorGUILayout.LabelField("Alterchase Mod Tester", EditorStyles.boldLabel);
            EditorGUILayout.HelpBox("Load and test your built mod packages in the Unity Editor.", MessageType.Info);
            EditorGUILayout.Space(10);

            DrawLoadSection();
            EditorGUILayout.Space(10);

            if (isLoaded && loadedPackage != null)
            {
                DrawPackageInfo();
                EditorGUILayout.Space(10);
                DrawTestControls();
            }
        }

        private void DrawLoadSection()
        {
            EditorGUILayout.LabelField("Load Mod Build", EditorStyles.boldLabel);
            
            EditorGUILayout.BeginHorizontal();
            selectedPackageForPath = (ModPackage)EditorGUILayout.ObjectField("Quick Load From:", selectedPackageForPath, typeof(ModPackage), false);
            if (GUILayout.Button("Get Path", GUILayout.Width(80)))
            {
                if (selectedPackageForPath != null)
                {
                    string packageName = selectedPackageForPath.PackageName.ToLower().Replace(" ", "");
                    string buildPath = Path.Combine(Application.dataPath, "..", selectedPackageForPath.BuildOutputPath, packageName, packageName + ".mod");
                    buildPath = Path.GetFullPath(buildPath);
                    
                    if (File.Exists(buildPath))
                    {
                        assetBundlePath = buildPath;
                        Debug.Log($"Found asset bundle at: {buildPath}");
                    }
                    else
                    {
                        EditorUtility.DisplayDialog("Asset Bundle Not Found", 
                            $"Could not find built asset bundle at:\n{buildPath}\n\nPlease build the package first using the Mod Package Builder.", 
                            "OK");
                    }
                }
            }
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.Space(5);
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.TextField("Bundle Path:", assetBundlePath);
            if (GUILayout.Button("Browse Folder", GUILayout.Width(120)))
            {
                string folderPath = EditorUtility.OpenFolderPanel("Select Mod Build Folder", "Builds/Mods", "");
                if (!string.IsNullOrEmpty(folderPath))
                {
                    string bundleFile = FindAssetBundleInFolder(folderPath);
                    if (!string.IsNullOrEmpty(bundleFile))
                    {
                        assetBundlePath = bundleFile;
                        Debug.Log($"Found asset bundle in folder: {bundleFile}");
                    }
                    else
                    {
                        EditorUtility.DisplayDialog("Asset Bundle Not Found", 
                            $"Could not find a valid asset bundle file (.mod) in:\n{folderPath}\n\nLooking for .mod file.", 
                            "OK");
                    }
                }
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space(10);

            GUI.enabled = !string.IsNullOrEmpty(assetBundlePath) && File.Exists(assetBundlePath);
            
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Load Bundle", GUILayout.Height(35)))
            {
                LoadAssetBundle();
            }
            
            if (GUILayout.Button("Load & Play Level", GUILayout.Height(35)))
            {
                LoadAndPlayLevel();
            }
            EditorGUILayout.EndHorizontal();
            
            GUI.enabled = true;

            GUI.enabled = isLoaded;
            if (GUILayout.Button("Unload", GUILayout.Height(30)))
            {
                UnloadAssetBundle();
            }
            GUI.enabled = true;
        }
        
        private string FindAssetBundleInFolder(string folderPath)
        {
            string folderName = Path.GetFileName(folderPath);
            
            string modFile = Path.Combine(folderPath, folderName + ".mod");
            if (File.Exists(modFile))
            {
                string scenesFile = Path.Combine(folderPath, folderName + "_scenes.mod");
                if (File.Exists(scenesFile))
                {
                    scenesBundlePath = scenesFile;
                    Debug.Log($"Found scenes bundle: {scenesFile}");
                }
                return modFile;
            }
            
            string directMatch = Path.Combine(folderPath, folderName);
            if (File.Exists(directMatch))
            {
                return directMatch;
            }
            
            string[] allFiles = Directory.GetFiles(folderPath);
            foreach (string file in allFiles)
            {
                string fileName = Path.GetFileName(file);
                string extension = Path.GetExtension(file);
                
                if (extension == ".mod" ||
                    string.IsNullOrEmpty(extension) || 
                    extension == ".bundle" || 
                    fileName == "StandaloneWindows64" ||
                    fileName == "StandaloneOSX" ||
                    fileName == "StandaloneLinux64")
                {
                    if (!fileName.EndsWith(".manifest") && !fileName.EndsWith(".meta") && !fileName.Contains("_scenes"))
                    {
                        return file;
                    }
                }
            }
            
            return null;
        }

        private void DrawPackageInfo()
        {
            EditorGUILayout.LabelField("Package Information", EditorStyles.boldLabel);
            
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            EditorGUILayout.LabelField("Name:", loadedPackage.PackageName, EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField("Author:", loadedPackage.AuthorName);
            EditorGUILayout.LabelField("Version:", loadedPackage.Version);
            EditorGUILayout.LabelField("Description:", loadedPackage.Description, EditorStyles.wordWrappedLabel);
            
            EditorGUILayout.Space(5);
            EditorGUILayout.LabelField($"Levels: {loadedLevels.Count}");
            EditorGUILayout.LabelField($"Models: {loadedModels.Count}");
            EditorGUILayout.LabelField($"Enemies: {loadedEnemies.Count}");
            EditorGUILayout.EndVertical();
        }

        private void DrawTestControls()
        {
            EditorGUILayout.LabelField("Test Controls", EditorStyles.boldLabel);
            
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            if (loadedLevels.Count > 0)
            {
                EditorGUILayout.LabelField("Levels", EditorStyles.boldLabel);
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                foreach (var level in loadedLevels)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField(level.AssetName, GUILayout.Width(200));
                    if (GUILayout.Button("Load & Test Scene", GUILayout.Width(150)))
                    {
                        LoadAndTestLevel(level);
                    }
                    EditorGUILayout.EndHorizontal();
                }
                EditorGUILayout.EndVertical();
                EditorGUILayout.Space(5);
            }

            if (loadedModels.Count > 0)
            {
                EditorGUILayout.LabelField("Models", EditorStyles.boldLabel);
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                foreach (var model in loadedModels)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField(model.AssetName, GUILayout.Width(200));
                    if (GUILayout.Button("Spawn in Scene", GUILayout.Width(150)))
                    {
                        SpawnModel(model);
                    }
                    EditorGUILayout.EndHorizontal();
                }
                EditorGUILayout.EndVertical();
                EditorGUILayout.Space(5);
            }

            if (loadedEnemies.Count > 0)
            {
                EditorGUILayout.LabelField("Enemies", EditorStyles.boldLabel);
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                foreach (var enemy in loadedEnemies)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField(enemy.AssetName, GUILayout.Width(200));
                    if (GUILayout.Button("Spawn in Scene", GUILayout.Width(150)))
                    {
                        SpawnEnemy(enemy);
                    }
                    EditorGUILayout.EndHorizontal();
                }
                EditorGUILayout.EndVertical();
                EditorGUILayout.Space(5);
            }

            EditorGUILayout.EndScrollView();

            EditorGUILayout.Space(10);
            
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Create Test Scene", GUILayout.Height(30)))
            {
                CreateTestScene();
            }
            
            GUI.enabled = !EditorApplication.isPlaying;
            if (GUILayout.Button("Enter Play Mode", GUILayout.Height(30)))
            {
                EditorApplication.isPlaying = true;
            }
            GUI.enabled = true;
            
            EditorGUILayout.EndHorizontal();
        }

        private void LoadAssetBundle()
        {
            try
            {
                if (loadedBundle != null)
                {
                    loadedBundle.Unload(true);
                }

                loadedBundle = AssetBundle.LoadFromFile(assetBundlePath);
                
                if (loadedBundle == null)
                {
                    EditorUtility.DisplayDialog("Error", "Failed to load asset bundle. Make sure the file is a valid Unity asset bundle.", "OK");
                    return;
                }

                string[] assetNames = loadedBundle.GetAllAssetNames();
                Debug.Log($"Asset Bundle loaded. Contains {assetNames.Length} assets:");
                foreach (string assetName in assetNames)
                {
                    Debug.Log($"  - {assetName}");
                }
                
                string[] scenePaths = loadedBundle.GetAllScenePaths();
                Debug.Log($"Scenes in bundle: {scenePaths.Length}");
                foreach (string scenePath in scenePaths)
                {
                    Debug.Log($"  - Scene: {scenePath}");
                }

                loadedPackage = null;
                
                ModPackage[] packages = loadedBundle.LoadAllAssets<ModPackage>();
                if (packages.Length > 0)
                {
                    loadedPackage = packages[0];
                    Debug.Log($"Found ModPackage: {loadedPackage.PackageName}");
                }
                else
                {
                    string packageAssetName = assetNames.FirstOrDefault(name => 
                        name.ToLower().Contains("modpackage") || 
                        name.ToLower().Contains("package") ||
                        name.EndsWith(".asset"));
                    
                    if (!string.IsNullOrEmpty(packageAssetName))
                    {
                        loadedPackage = loadedBundle.LoadAsset<ModPackage>(packageAssetName);
                    }
                }

                if (loadedPackage != null)
                {
                    loadedLevels = loadedBundle.LoadAllAssets<LevelModAsset>().ToList();
                    loadedModels = loadedBundle.LoadAllAssets<ModelModAsset>().ToList();
                    loadedEnemies = loadedBundle.LoadAllAssets<EnemyModAsset>().ToList();

                    isLoaded = true;
                    Debug.Log($"Mod Package '{loadedPackage.PackageName}' loaded successfully!");
                    Debug.Log($"Loaded: {loadedLevels.Count} levels, {loadedModels.Count} models, {loadedEnemies.Count} enemies");
                }
                else
                {
                    string assetList = string.Join("\n", assetNames);
                    EditorUtility.DisplayDialog("Error", 
                        $"Could not find ModPackage in the asset bundle.\n\nAssets found:\n{assetList}\n\nMake sure your ModPackage is included in the build.", 
                        "OK");
                    loadedBundle.Unload(true);
                    loadedBundle = null;
                }
            }
            catch (System.Exception e)
            {
                EditorUtility.DisplayDialog("Error", $"Failed to load asset bundle:\n{e.Message}", "OK");
                Debug.LogError($"Asset bundle load error: {e}");
                if (loadedBundle != null)
                {
                    loadedBundle.Unload(true);
                    loadedBundle = null;
                }
            }
        }

        private void UnloadAssetBundle()
        {
            if (loadedBundle != null)
            {
                loadedBundle.Unload(true);
                loadedBundle = null;
            }

            loadedPackage = null;
            loadedLevels.Clear();
            loadedModels.Clear();
            loadedEnemies.Clear();
            isLoaded = false;

            Debug.Log("Asset bundle unloaded.");
        }
        
        private void LoadAndPlayLevel()
        {
            LoadAssetBundle();
            
            if (!isLoaded || loadedLevels.Count == 0)
            {
                EditorUtility.DisplayDialog("No Levels Found", 
                    "The loaded mod package does not contain any levels to test.", 
                    "OK");
                return;
            }
            
            LevelModAsset firstLevel = loadedLevels[0];
            
            if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
            {
                CreateTestSceneForLevel(firstLevel);
                
                EditorApplication.isPlaying = true;
                
                Debug.Log($"Entering Play Mode to test level: {firstLevel.AssetName}");
            }
        }

        private void LoadAndTestLevel(LevelModAsset level)
        {
            if (level == null)
            {
                EditorUtility.DisplayDialog("Error", "Level asset is null.", "OK");
                return;
            }

            string scenePath = level.ScenePath;
            
            if (string.IsNullOrEmpty(scenePath))
            {
                EditorUtility.DisplayDialog("Error", "Level does not have a valid scene path.", "OK");
                return;
            }

            if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
            {
                CreateTestSceneForLevel(level);
                
                EditorUtility.DisplayDialog("Level Loaded", 
                    $"Test scene created for '{level.AssetName}'.\n\nClick 'Enter Play Mode' to test the level.", 
                    "OK");
            }
        }

        private void CreateTestSceneForLevel(LevelModAsset level)
        {
            var newScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
            
            GameObject camera = GameObject.FindFirstObjectByType<Camera>()?.gameObject;
            if (camera != null)
            {
                camera.name = "Test Camera";
                camera.tag = "MainCamera";
            }
            
            GameObject light = GameObject.FindFirstObjectByType<Light>()?.gameObject;
            if (light != null)
            {
                light.name = "Test Directional Light";
                Light lightComp = light.GetComponent<Light>();
                lightComp.type = LightType.Directional;
                lightComp.intensity = 1f;
                light.transform.rotation = Quaternion.Euler(50, -30, 0);
            }
            
            GameObject modLoaderObj = new GameObject("ModLoader");
            ModLoaderTestHelper helper = modLoaderObj.AddComponent<ModLoaderTestHelper>();
            helper.assetBundlePath = assetBundlePath;
            helper.levelToLoad = level.AssetName;
            helper.autoSpawnModels = false;
            helper.autoSpawnEnemies = false;
            
            EditorSceneManager.MarkSceneDirty(newScene);
            
            Debug.Log($"Test scene created for level: {level.AssetName}");
            Debug.Log($"  - Camera: {(camera != null ? "Ready" : "Not found")}");
            Debug.Log($"  - Lighting: {(light != null ? "Ready" : "Not found")}");
            Debug.Log($"  - ModLoader: Configured to load '{level.AssetName}'");
        }

        private void SpawnModel(ModelModAsset model)
        {
            if (model == null || model.ModelPrefab == null)
            {
                EditorUtility.DisplayDialog("Error", "Model prefab is not assigned or is null.", "OK");
                return;
            }

            Vector3 spawnPosition = GetSpawnPosition();
            GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(model.ModelPrefab);
            instance.transform.position = spawnPosition;
            instance.name = $"{model.AssetName} (Test)";

            Selection.activeGameObject = instance;
            SceneView.FrameLastActiveSceneView();

            Debug.Log($"Spawned model '{model.AssetName}' at {spawnPosition}");
        }

        private void SpawnEnemy(EnemyModAsset enemy)
        {
            if (enemy == null || enemy.EnemyPrefab == null)
            {
                EditorUtility.DisplayDialog("Error", "Enemy prefab is not assigned or is null.", "OK");
                return;
            }

            Vector3 spawnPosition = GetSpawnPosition();
            GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(enemy.EnemyPrefab);
            instance.transform.position = spawnPosition;
            instance.name = $"{enemy.AssetName} (Test)";

            Selection.activeGameObject = instance;
            SceneView.FrameLastActiveSceneView();

            Debug.Log($"Spawned enemy '{enemy.AssetName}' at {spawnPosition}");
        }

        private Vector3 GetSpawnPosition()
        {
            if (SceneView.lastActiveSceneView != null && SceneView.lastActiveSceneView.camera != null)
            {
                Camera sceneCamera = SceneView.lastActiveSceneView.camera;
                return sceneCamera.transform.position + sceneCamera.transform.forward * 5f;
            }

            if (Selection.activeGameObject != null)
            {
                return Selection.activeGameObject.transform.position + Vector3.right * 2f;
            }

            return Vector3.zero;
        }

        private void CreateTestScene()
        {
            if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
            {
                var newScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);

                GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Plane);
                floor.name = "Test Floor";
                floor.transform.localScale = new Vector3(10, 1, 10);

                GameObject modLoaderObj = new GameObject("ModLoader");
                ModLoaderTestHelper helper = modLoaderObj.AddComponent<ModLoaderTestHelper>();
                helper.assetBundlePath = assetBundlePath;

                if (Camera.main != null)
                {
                    Camera.main.transform.position = new Vector3(0, 5, -10);
                    Camera.main.transform.LookAt(Vector3.zero);
                }

                EditorSceneManager.MarkSceneDirty(newScene);
                
                Debug.Log("Test scene created. Add your mod assets and enter Play Mode to test.");
            }
        }

        private void OnDisable()
        {
            if (loadedBundle != null && !EditorApplication.isPlaying)
            {
                loadedBundle.Unload(false);
            }
        }
    }
}
