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

namespace AlterchaseSDK.Editor
{
    public class AssetBoxWindow : EditorWindow
    {
        private const string ASSET_BOX_FOLDER = "Assets/Scripts/AlterchaseSDK/AssetBoxAssets";
        
        private List<AssetBoxItem> assetItems = new List<AssetBoxItem>();
        private Vector2 scrollPosition;
        private string searchFilter = "";
        private float iconSize = 80f;
        private int itemsPerRow = 4;

        private class AssetBoxItem
        {
            public Object asset;
            public string name;
            public string path;
            public Texture2D preview;
            public bool isPrefab;
        }

        [MenuItem("Alterchase SDK/Asset Box", priority = 2)]
        public static void ShowWindow()
        {
            AssetBoxWindow window = GetWindow<AssetBoxWindow>("Asset Box");
            window.minSize = new Vector2(400, 500);
            window.Show();
        }

        private void OnEnable()
        {
            EnsureAssetBoxFolderExists();
            RefreshAssets();
        }

        private void OnGUI()
        {
            DrawHeader();
            DrawToolbar();
            
            EditorGUILayout.Space(5);
            
            DrawAssetGrid();
        }

        private void DrawHeader()
        {
            EditorGUILayout.BeginVertical("box");
            
            GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel)
            {
                fontSize = 16,
                alignment = TextAnchor.MiddleLeft
            };
            
            EditorGUILayout.LabelField("Asset Box", headerStyle);
            EditorGUILayout.LabelField("Drag assets from here into your scene", EditorStyles.miniLabel);
            
            EditorGUILayout.EndVertical();
        }

        private void DrawToolbar()
        {
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
            
            GUILayout.Label("Search:", GUILayout.Width(50));
            searchFilter = EditorGUILayout.TextField(searchFilter, EditorStyles.toolbarTextField);
            
            if (GUILayout.Button("Clear", EditorStyles.toolbarButton, GUILayout.Width(50)))
            {
                searchFilter = "";
                GUI.FocusControl(null);
            }
            
            GUILayout.FlexibleSpace();
            
            if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60)))
            {
                RefreshAssets();
            }
            
            if (GUILayout.Button("Add Assets", EditorStyles.toolbarButton, GUILayout.Width(80)))
            {
                ShowAddAssetsMenu();
            }
            
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
            
            GUILayout.Label("Icon Size:", GUILayout.Width(70));
            iconSize = EditorGUILayout.Slider(iconSize, 60f, 120f, GUILayout.Width(150));
            
            GUILayout.FlexibleSpace();
            
            GUILayout.Label($"Assets: {GetFilteredAssets().Count}", EditorStyles.miniLabel);
            
            EditorGUILayout.EndHorizontal();
        }

        private void DrawAssetGrid()
        {
            List<AssetBoxItem> filteredAssets = GetFilteredAssets();
            
            if (filteredAssets.Count == 0)
            {
                EditorGUILayout.Space(20);
                EditorGUILayout.HelpBox(
                    string.IsNullOrEmpty(searchFilter) 
                        ? "No assets in Asset Box.\n\nClick 'Add Assets' to add models or prefabs." 
                        : "No assets match your search.",
                    MessageType.Info
                );
                return;
            }
            
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            
            float windowWidth = position.width - 20;
            itemsPerRow = Mathf.Max(1, Mathf.FloorToInt(windowWidth / (iconSize + 10)));
            
            int currentColumn = 0;
            EditorGUILayout.BeginHorizontal();
            
            foreach (AssetBoxItem item in filteredAssets)
            {
                if (currentColumn >= itemsPerRow)
                {
                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.BeginHorizontal();
                    currentColumn = 0;
                }
                
                DrawAssetItem(item);
                currentColumn++;
            }
            
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.EndScrollView();
        }

        private void DrawAssetItem(AssetBoxItem item)
        {
            EditorGUILayout.BeginVertical(GUILayout.Width(iconSize + 10));
            
            Rect dropRect = GUILayoutUtility.GetRect(iconSize, iconSize, GUILayout.Width(iconSize));
            
            GUI.Box(dropRect, "", "box");
            
            if (item.preview != null)
            {
                GUI.DrawTexture(dropRect.Shrink(2), item.preview, ScaleMode.ScaleToFit);
            }
            else
            {
                Texture2D icon = item.isPrefab 
                    ? EditorGUIUtility.IconContent("Prefab Icon").image as Texture2D
                    : EditorGUIUtility.IconContent("GameObject Icon").image as Texture2D;
                
                if (icon != null)
                {
                    GUI.DrawTexture(dropRect.Shrink(20), icon, ScaleMode.ScaleToFit);
                }
            }
            
            if (Event.current.type == EventType.MouseDown && dropRect.Contains(Event.current.mousePosition))
            {
                DragAndDrop.PrepareStartDrag();
                DragAndDrop.objectReferences = new Object[] { item.asset };
                DragAndDrop.StartDrag(item.name);
                Event.current.Use();
            }
            
            GUIStyle labelStyle = new GUIStyle(EditorStyles.label)
            {
                alignment = TextAnchor.MiddleCenter,
                wordWrap = true,
                fontSize = 10
            };
            
            EditorGUILayout.LabelField(item.name, labelStyle, GUILayout.Height(30), GUILayout.Width(iconSize + 10));
            
            if (GUILayout.Button("Select", GUILayout.Width(iconSize + 10)))
            {
                Selection.activeObject = item.asset;
                EditorGUIUtility.PingObject(item.asset);
            }
            
            EditorGUILayout.EndVertical();
        }

        private List<AssetBoxItem> GetFilteredAssets()
        {
            if (string.IsNullOrEmpty(searchFilter))
            {
                return assetItems;
            }
            
            string filter = searchFilter.ToLower();
            return assetItems.Where(item => item.name.ToLower().Contains(filter)).ToList();
        }

        private void RefreshAssets()
        {
            assetItems.Clear();
            
            if (!AssetDatabase.IsValidFolder(ASSET_BOX_FOLDER))
            {
                return;
            }
            
            string[] allAssets = AssetDatabase.FindAssets("t:GameObject t:Model", new[] { ASSET_BOX_FOLDER });
            
            foreach (string guid in allAssets)
            {
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                Object asset = AssetDatabase.LoadAssetAtPath<Object>(assetPath);
                
                if (asset == null) continue;
                
                bool isPrefab = assetPath.EndsWith(".prefab");
                bool isModel = assetPath.EndsWith(".fbx") || assetPath.EndsWith(".obj") || 
                              assetPath.EndsWith(".dae") || assetPath.EndsWith(".blend") || 
                              assetPath.EndsWith(".3ds");
                
                if (!isPrefab && !isModel) continue;
                
                AssetBoxItem item = new AssetBoxItem
                {
                    asset = asset,
                    name = Path.GetFileNameWithoutExtension(assetPath),
                    path = assetPath,
                    isPrefab = isPrefab,
                    preview = AssetPreview.GetAssetPreview(asset)
                };
                
                assetItems.Add(item);
            }
            
            assetItems = assetItems.OrderBy(item => item.name).ToList();
            
            Repaint();
        }

        private void ShowAddAssetsMenu()
        {
            GenericMenu menu = new GenericMenu();
            
            menu.AddItem(new GUIContent("Add Selected Assets"), false, AddSelectedAssets);
            menu.AddItem(new GUIContent("Import Assets..."), false, ImportAssets);
            menu.AddSeparator("");
            menu.AddItem(new GUIContent("Open Asset Box Folder"), false, OpenAssetBoxFolder);
            menu.AddItem(new GUIContent("Remove All Assets"), false, ConfirmRemoveAllAssets);
            
            menu.ShowAsContext();
        }

        private void AddSelectedAssets()
        {
            Object[] selectedObjects = Selection.objects;
            
            if (selectedObjects.Length == 0)
            {
                EditorUtility.DisplayDialog("No Selection", "Please select one or more prefabs or models to add to the Asset Box.", "OK");
                return;
            }
            
            int addedCount = 0;
            
            foreach (Object obj in selectedObjects)
            {
                string sourcePath = AssetDatabase.GetAssetPath(obj);
                
                if (string.IsNullOrEmpty(sourcePath)) continue;
                
                bool isPrefab = sourcePath.EndsWith(".prefab");
                bool isModel = sourcePath.EndsWith(".fbx") || sourcePath.EndsWith(".obj") || 
                              sourcePath.EndsWith(".dae") || sourcePath.EndsWith(".blend") || 
                              sourcePath.EndsWith(".3ds");
                
                if (!isPrefab && !isModel) continue;
                
                if (sourcePath.StartsWith(ASSET_BOX_FOLDER))
                {
                    Debug.LogWarning($"Asset '{obj.name}' is already in the Asset Box.");
                    continue;
                }
                
                string fileName = Path.GetFileName(sourcePath);
                string targetPath = Path.Combine(ASSET_BOX_FOLDER, fileName);
                
                if (File.Exists(targetPath))
                {
                    targetPath = AssetDatabase.GenerateUniqueAssetPath(targetPath);
                }
                
                if (AssetDatabase.CopyAsset(sourcePath, targetPath))
                {
                    addedCount++;
                }
            }
            
            if (addedCount > 0)
            {
                AssetDatabase.Refresh();
                RefreshAssets();
                EditorUtility.DisplayDialog("Assets Added", $"Successfully added {addedCount} asset(s) to the Asset Box.", "OK");
            }
            else
            {
                EditorUtility.DisplayDialog("No Assets Added", "No valid prefabs or models were selected.", "OK");
            }
        }

        private void ImportAssets()
        {
            string path = EditorUtility.OpenFilePanelWithFilters(
                "Import Asset to Asset Box",
                "",
                new string[] { "Models", "fbx,obj,dae,blend,3ds", "Prefabs", "prefab" }
            );
            
            if (string.IsNullOrEmpty(path)) return;
            
            string projectPath = Application.dataPath;
            
            if (path.StartsWith(projectPath))
            {
                string relativePath = "Assets" + path.Substring(projectPath.Length);
                
                string fileName = Path.GetFileName(relativePath);
                string targetPath = Path.Combine(ASSET_BOX_FOLDER, fileName);
                
                if (AssetDatabase.CopyAsset(relativePath, targetPath))
                {
                    AssetDatabase.Refresh();
                    RefreshAssets();
                    EditorUtility.DisplayDialog("Asset Imported", $"Successfully imported '{fileName}' to the Asset Box.", "OK");
                }
            }
            else
            {
                EditorUtility.DisplayDialog("Invalid Path", "Please select an asset from within your Unity project.", "OK");
            }
        }

        private void OpenAssetBoxFolder()
        {
            Object folder = AssetDatabase.LoadAssetAtPath<Object>(ASSET_BOX_FOLDER);
            Selection.activeObject = folder;
            EditorGUIUtility.PingObject(folder);
        }

        private void ConfirmRemoveAllAssets()
        {
            if (EditorUtility.DisplayDialog(
                "Remove All Assets?",
                "This will remove all assets from the Asset Box folder. This action cannot be undone.\n\nAre you sure?",
                "Remove All",
                "Cancel"))
            {
                RemoveAllAssets();
            }
        }

        private void RemoveAllAssets()
        {
            string[] allFiles = Directory.GetFiles(ASSET_BOX_FOLDER);
            
            foreach (string file in allFiles)
            {
                if (file.EndsWith(".meta")) continue;
                
                string assetPath = file.Replace("\\", "/");
                AssetDatabase.DeleteAsset(assetPath);
            }
            
            AssetDatabase.Refresh();
            RefreshAssets();
            
            EditorUtility.DisplayDialog("Assets Removed", "All assets have been removed from the Asset Box.", "OK");
        }

        private void EnsureAssetBoxFolderExists()
        {
            string[] pathParts = ASSET_BOX_FOLDER.Split('/');
            string currentPath = pathParts[0];
            
            for (int i = 1; i < pathParts.Length; i++)
            {
                string nextPath = currentPath + "/" + pathParts[i];
                
                if (!AssetDatabase.IsValidFolder(nextPath))
                {
                    AssetDatabase.CreateFolder(currentPath, pathParts[i]);
                }
                
                currentPath = nextPath;
            }
            
            AssetDatabase.Refresh();
        }
    }

    public static class RectExtensions
    {
        public static Rect Shrink(this Rect rect, float amount)
        {
            return new Rect(
                rect.x + amount,
                rect.y + amount,
                rect.width - amount * 2,
                rect.height - amount * 2
            );
        }
    }
}
