using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using UnityEditor;
using UnityEngine;

namespace AlterchaseSDK.Editor
{
    public class ModPackageBuilder : EditorWindow
    {
        private ModPackage selectedPackage;
        private Vector2 scrollPosition;
        private bool showValidationErrors = false;
        private List<string> validationErrors = new List<string>();
        
        private enum BuildMode
        {
            BuildsFolder,
            ZipFile
        }
        
        private BuildMode selectedBuildMode = BuildMode.BuildsFolder;

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

        private void OnGUI()
        {
            DrawHeader();
            
            EditorGUILayout.Space(10);
            
            DrawPackageSelection();
            
            if (selectedPackage != null)
            {
                EditorGUILayout.Space(10);
                DrawPackageInfo();
                
                EditorGUILayout.Space(10);
                DrawAssetCounts();
                
                EditorGUILayout.Space(10);
                DrawValidation();
                
                EditorGUILayout.Space(10);
                DrawBuildOptions();
            }
            else
            {
                EditorGUILayout.HelpBox("Select a Mod Package to begin building.", MessageType.Info);
            }
        }

        private void DrawHeader()
        {
            EditorGUILayout.LabelField("Alterchase Mod Package Builder", EditorStyles.boldLabel);
            EditorGUILayout.LabelField("Build and validate your mod packages for distribution.", EditorStyles.miniLabel);
            EditorGUILayout.Space(5);
            EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
        }

        private void DrawPackageSelection()
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Mod Package", GUILayout.Width(100));
            selectedPackage = EditorGUILayout.ObjectField(selectedPackage, typeof(ModPackage), false) as ModPackage;
            
            if (GUILayout.Button("Create New", GUILayout.Width(100)))
            {
                CreateNewModPackage();
            }
            EditorGUILayout.EndHorizontal();
        }

        private void DrawPackageInfo()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField("Package Information", EditorStyles.boldLabel);
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Name:", GUILayout.Width(100));
            EditorGUILayout.LabelField(selectedPackage.PackageName);
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Author:", GUILayout.Width(100));
            EditorGUILayout.LabelField(selectedPackage.AuthorName);
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Version:", GUILayout.Width(100));
            EditorGUILayout.LabelField(selectedPackage.Version);
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Package ID:", GUILayout.Width(100));
            EditorGUILayout.SelectableLabel(selectedPackage.PackageID.ToString(), EditorStyles.miniLabel, GUILayout.Height(18));
            EditorGUILayout.EndHorizontal();
            
            if (GUILayout.Button("Edit Package Settings"))
            {
                Selection.activeObject = selectedPackage;
            }
            
            EditorGUILayout.EndVertical();
        }

        private void DrawAssetCounts()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField("Package Contents", EditorStyles.boldLabel);
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField($"Levels: {selectedPackage.Levels.Count}", GUILayout.Width(150));
            EditorGUILayout.LabelField($"Models: {selectedPackage.Models.Count}", GUILayout.Width(150));
            EditorGUILayout.LabelField($"Enemies: {selectedPackage.Enemies.Count}");
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.LabelField($"Total Assets: {selectedPackage.GetTotalAssetCount()}", EditorStyles.boldLabel);
            
            EditorGUILayout.EndVertical();
        }

        private void DrawValidation()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField("Validation", EditorStyles.boldLabel);
            
            if (GUILayout.Button("Validate Package"))
            {
                ValidatePackage();
            }
            
            if (showValidationErrors)
            {
                if (validationErrors.Count == 0)
                {
                    EditorGUILayout.HelpBox("Package validation passed! Ready to build.", MessageType.Info);
                }
                else
                {
                    EditorGUILayout.HelpBox($"Found {validationErrors.Count} validation error(s):", MessageType.Error);
                    
                    scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(100));
                    foreach (string error in validationErrors)
                    {
                        EditorGUILayout.LabelField("• " + error, EditorStyles.wordWrappedMiniLabel);
                    }
                    EditorGUILayout.EndScrollView();
                }
            }
            
            EditorGUILayout.EndVertical();
        }

        private void DrawBuildOptions()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField("Build Options", EditorStyles.boldLabel);
            
            EditorGUILayout.Space(5);
            
            EditorGUILayout.LabelField("Build Mode:", EditorStyles.boldLabel);
            selectedBuildMode = (BuildMode)EditorGUILayout.EnumPopup("Mode:", selectedBuildMode);
            
            EditorGUILayout.Space(3);
            
            if (selectedBuildMode == BuildMode.BuildsFolder)
            {
                EditorGUILayout.HelpBox("Build to the game's builds folder for local testing.", MessageType.Info);
                
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Output Path:", GUILayout.Width(100));
                EditorGUILayout.LabelField(selectedPackage.BuildOutputPath, EditorStyles.miniLabel);
                EditorGUILayout.EndHorizontal();
            }
            else
            {
                EditorGUILayout.HelpBox("Build and package as a zip file ready for mod.io upload.", MessageType.Info);
                
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Output Path:", GUILayout.Width(100));
                EditorGUILayout.LabelField("Builds/ModIOPackages/", EditorStyles.miniLabel);
                EditorGUILayout.EndHorizontal();
            }
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Build Target:", GUILayout.Width(100));
            EditorGUILayout.LabelField(selectedPackage.BuildTarget.ToString(), EditorStyles.miniLabel);
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.Space(5);
            
            string buttonLabel = selectedBuildMode == BuildMode.BuildsFolder 
                ? "Build Asset Bundles" 
                : "Build and Package for mod.io";
            
            if (GUILayout.Button(buttonLabel, GUILayout.Height(30)))
            {
                BuildAssetBundles();
            }
            
            EditorGUILayout.EndVertical();
        }

        private void ValidatePackage()
        {
            showValidationErrors = true;
            bool isValid = selectedPackage.ValidatePackage(out validationErrors);
            
            if (isValid)
            {
                Debug.Log($"Package '{selectedPackage.PackageName}' validation passed!");
            }
            else
            {
                Debug.LogWarning($"Package '{selectedPackage.PackageName}' has validation errors. See Mod Package Builder window for details.");
            }
        }

        private void BuildAssetBundles()
        {
            if (!selectedPackage.ValidatePackage(out List<string> errors))
            {
                EditorUtility.DisplayDialog("Validation Failed", 
                    $"Cannot build package due to validation errors:\n\n{string.Join("\n", errors)}", 
                    "OK");
                showValidationErrors = true;
                validationErrors = errors;
                return;
            }

            string packageNameLower = selectedPackage.PackageName.ToLower().Replace(" ", "");
            string outputPath;
            
            if (selectedBuildMode == BuildMode.ZipFile)
            {
                outputPath = Path.Combine(Application.dataPath, "..", "Builds", "ModIOPackages", packageNameLower);
            }
            else
            {
                outputPath = Path.Combine(Application.dataPath, "..", selectedPackage.BuildOutputPath, packageNameLower);
            }
            
            if (!Directory.Exists(outputPath))
            {
                Directory.CreateDirectory(outputPath);
            }

            List<AssetBundleBuild> builds = new List<AssetBundleBuild>();
            List<string> assetPaths = new List<string>();
            List<string> scenePaths = new List<string>();
            
            string packagePath = AssetDatabase.GetAssetPath(selectedPackage);
            assetPaths.Add(packagePath);
            
            Debug.Log($"Adding ModPackage to bundle: {packagePath}");
            string[] packageDependencies = AssetDatabase.GetDependencies(packagePath, true);
            foreach (string dep in packageDependencies)
            {
                if (!dep.EndsWith(".cs") && !assetPaths.Contains(dep))
                {
                    assetPaths.Add(dep);
                    Debug.Log($"  + Dependency: {dep}");
                }
            }

            if (selectedPackage.Levels.Count > 0)
            {
                string[] levelPaths = GetAssetPaths(selectedPackage.Levels);
                foreach (string levelPath in levelPaths)
                {
                    if (!assetPaths.Contains(levelPath))
                    {
                        assetPaths.Add(levelPath);
                    }
                    
                    string[] levelDeps = AssetDatabase.GetDependencies(levelPath, true);
                    foreach (string dep in levelDeps)
                    {
                        if (!dep.EndsWith(".cs") && !assetPaths.Contains(dep) && !dep.Contains("/Scenes/"))
                        {
                            assetPaths.Add(dep);
                        }
                    }
                }
                
                foreach (var level in selectedPackage.Levels)
                {
                    if (!string.IsNullOrEmpty(level.ScenePath))
                    {
                        if (System.IO.File.Exists(level.ScenePath))
                        {
                            scenePaths.Add(level.ScenePath);
                            Debug.Log($"Adding scene to scenes bundle: {level.ScenePath}");
                        }
                        else
                        {
                            Debug.LogWarning($"Scene not found: {level.ScenePath}");
                        }
                    }
                }
            }

            if (selectedPackage.Models.Count > 0)
            {
                string[] modelPaths = GetAssetPaths(selectedPackage.Models);
                foreach (string modelPath in modelPaths)
                {
                    if (!assetPaths.Contains(modelPath))
                    {
                        assetPaths.Add(modelPath);
                    }
                    
                    string[] modelDeps = AssetDatabase.GetDependencies(modelPath, true);
                    foreach (string dep in modelDeps)
                    {
                        if (!dep.EndsWith(".cs") && !assetPaths.Contains(dep))
                        {
                            assetPaths.Add(dep);
                        }
                    }
                }
            }

            if (selectedPackage.Enemies.Count > 0)
            {
                string[] enemyPaths = GetAssetPaths(selectedPackage.Enemies);
                foreach (string enemyPath in enemyPaths)
                {
                    if (!assetPaths.Contains(enemyPath))
                    {
                        assetPaths.Add(enemyPath);
                    }
                    
                    string[] enemyDeps = AssetDatabase.GetDependencies(enemyPath, true);
                    foreach (string dep in enemyDeps)
                    {
                        if (!dep.EndsWith(".cs") && !assetPaths.Contains(dep))
                        {
                            assetPaths.Add(dep);
                        }
                    }
                }
            }

            string bundleName = $"{packageNameLower}.mod";
            
            AssetBundleBuild assetsBundle = new AssetBundleBuild
            {
                assetBundleName = bundleName,
                assetNames = assetPaths.ToArray()
            };
            builds.Add(assetsBundle);
            
            if (scenePaths.Count > 0)
            {
                string scenesBundleName = $"{packageNameLower}_scenes.mod";
                AssetBundleBuild scenesBundle = new AssetBundleBuild
                {
                    assetBundleName = scenesBundleName,
                    assetNames = scenePaths.ToArray()
                };
                builds.Add(scenesBundle);
                Debug.Log($"Creating separate scenes bundle: {scenesBundleName} with {scenePaths.Count} scenes");
            }

            UnityEditor.BuildTarget buildTarget = ConvertBuildTarget(selectedPackage.BuildTarget);
            
            Debug.Log($"Building {builds.Count} asset bundles:");
            Debug.Log($"  - Assets bundle: {bundleName} ({assetPaths.Count} assets including dependencies)");
            if (scenePaths.Count > 0)
            {
                Debug.Log($"  - Scenes bundle: {packageNameLower}_scenes.mod ({scenePaths.Count} scenes)");
            }
            
            BuildPipeline.BuildAssetBundles(outputPath, builds.ToArray(), 
                BuildAssetBundleOptions.None, buildTarget);

            AssetDatabase.Refresh();
            
            if (selectedBuildMode == BuildMode.ZipFile)
            {
                CreateModIOPackage(outputPath, packageNameLower, bundleName, assetPaths.Count, scenePaths.Count);
            }
            else
            {
                EditorUtility.DisplayDialog("Build Complete", 
                    $"Successfully built mod to:\n{outputPath}\n\nAssets: {bundleName} ({assetPaths.Count} assets)\nScenes: {packageNameLower}_scenes.mod ({scenePaths.Count} scenes)", 
                    "OK");
                
                Debug.Log($"Mod package '{selectedPackage.PackageName}' built successfully!");
                Debug.Log($"  Output: {outputPath}");
                Debug.Log($"  Bundle: {bundleName}");
                Debug.Log($"  Assets included: {assetPaths.Count}");
                foreach (string assetPath in assetPaths)
                {
                    Debug.Log($"    - {assetPath}");
                }
            }
        }

        private void CreateModIOPackage(string buildPath, string packageNameLower, string bundleName, int assetCount, int sceneCount)
        {
            string zipOutputDir = Path.Combine(Application.dataPath, "..", "Builds", "ModIOPackages");
            if (!Directory.Exists(zipOutputDir))
            {
                Directory.CreateDirectory(zipOutputDir);
            }
            
            string zipFileName = $"{packageNameLower}_v{selectedPackage.Version}.zip";
            string zipFilePath = Path.Combine(zipOutputDir, zipFileName);
            
            if (File.Exists(zipFilePath))
            {
                File.Delete(zipFilePath);
            }
            
            try
            {
                using (FileStream zipStream = new FileStream(zipFilePath, FileMode.Create))
                using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create))
                {
                    string[] files = Directory.GetFiles(buildPath);
                    
                    foreach (string filePath in files)
                    {
                        string fileName = Path.GetFileName(filePath);
                        
                        if (fileName.EndsWith(".mod") || fileName.EndsWith(".manifest"))
                        {
                            archive.CreateEntryFromFile(filePath, fileName, System.IO.Compression.CompressionLevel.Optimal);
                            Debug.Log($"Added to zip: {fileName}");
                        }
                    }
                }
                
                Debug.Log($"Mod package '{selectedPackage.PackageName}' built and packaged successfully!");
                Debug.Log($"  Build output: {buildPath}");
                Debug.Log($"  Zip package: {zipFilePath}");
                Debug.Log($"  Assets bundle: {bundleName} ({assetCount} assets)");
                Debug.Log($"  Scenes bundle: {packageNameLower}_scenes.mod ({sceneCount} scenes)");
                
                bool openFolder = EditorUtility.DisplayDialog("Build Complete", 
                    $"Successfully built and packaged mod for mod.io!\n\nZip file: {zipFileName}\nLocation: {zipOutputDir}\n\nAssets: {bundleName} ({assetCount} assets)\nScenes: {packageNameLower}_scenes.mod ({sceneCount} scenes)\n\nOpen output folder?", 
                    "Open Folder", 
                    "Close");
                
                if (openFolder)
                {
                    EditorUtility.RevealInFinder(zipFilePath);
                }
            }
            catch (System.Exception e)
            {
                Debug.LogError($"Failed to create zip package: {e.Message}");
                EditorUtility.DisplayDialog("Build Error", 
                    $"Failed to create zip package:\n{e.Message}", 
                    "OK");
            }
        }

        private string[] GetAssetPaths<T>(List<T> assets) where T : ModAsset
        {
            List<string> paths = new List<string>();
            foreach (var asset in assets)
            {
                if (asset != null)
                {
                    string path = AssetDatabase.GetAssetPath(asset);
                    paths.Add(path);
                }
            }
            return paths.ToArray();
        }

        private UnityEditor.BuildTarget ConvertBuildTarget(AlterchaseSDK.BuildTarget target)
        {
            switch (target)
            {
                case AlterchaseSDK.BuildTarget.StandaloneWindows64:
                    return UnityEditor.BuildTarget.StandaloneWindows64;
                case AlterchaseSDK.BuildTarget.StandaloneOSX:
                    return UnityEditor.BuildTarget.StandaloneOSX;
                case AlterchaseSDK.BuildTarget.StandaloneLinux64:
                    return UnityEditor.BuildTarget.StandaloneLinux64;
                case AlterchaseSDK.BuildTarget.Android:
                    return UnityEditor.BuildTarget.Android;
                case AlterchaseSDK.BuildTarget.iOS:
                    return UnityEditor.BuildTarget.iOS;
                default:
                    return UnityEditor.BuildTarget.StandaloneWindows64;
            }
        }

        private void CreateNewModPackage()
        {
            string path = EditorUtility.SaveFilePanelInProject(
                "Create New Mod Package",
                "NewModPackage",
                "asset",
                "Choose a location to save the new Mod Package");

            if (!string.IsNullOrEmpty(path))
            {
                ModPackage newPackage = CreateInstance<ModPackage>();
                AssetDatabase.CreateAsset(newPackage, path);
                AssetDatabase.SaveAssets();
                selectedPackage = newPackage;
                Selection.activeObject = newPackage;
            }
        }
    }
}
