using System;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using AssetBank.Settings;
using System.Collections.Generic;
using IntelligentProjectAnalyzer.Helper;

namespace AssetBank.Editor.Tools
{
    public static class GuidMapperExporter
    {
        public enum ExportFor
        {
            Script,
            Scene,
            Prefab,
            ScriptableObject,
            All
        }
        
        private static readonly string[] CommonModelExtensions = { ".fbx", ".obj", ".dae", ".gltf", ".glb", ".usdz", ".ply" };
        
        [Serializable]
        public class GuidMapper
        {
            public string Guid { get; set; }
            public string Path { get; set; }
        }

        [MenuItem("Tools/Exporter/GUID Exporter/Export Script GUIDs")]
        public static void ExportScriptGuids()
        {
            Export(ExportFor.Script);
        }
        
        [MenuItem("Tools/Exporter/GUID Exporter/Export Scene GUIDs")]
        public static void ExportSceneGuids()
        {
            Export(ExportFor.Scene);
        }
        
        [MenuItem("Tools/Exporter/GUID Exporter/Export Prefab GUIDs")]
        public static void ExportPrefabGuids()
        {
            Export(ExportFor.Prefab);
        }
        
        [MenuItem("Tools/Exporter/GUID Exporter/Export ScriptableObject GUIDs")]
        public static void ExportScriptableObjectGuids()
        {
            Export(ExportFor.ScriptableObject);
        }
        
        private static void Export(ExportFor exportFor)
        {
            var (searchPattern, extension) = GetSearchPattern(exportFor);
            var searchResults = AssetDatabase.FindAssets(searchPattern, new[] { "Assets" });
            
            var settings = ProjectExporterSettings.GetOrCreateSettings();
            var folderToIgnore = settings.FoldersToIgnore;
            var mapperList = new List<GuidMapper>();
            
            foreach (var guid in searchResults)
            {
                var path = AssetDatabase.GUIDToAssetPath(guid);
                if (extension != "*" && !path.EndsWith(extension)) continue;
                
                var directoryName = Path.GetDirectoryName(path);
                if (folderToIgnore.Any(folder => directoryName != null && directoryName.StartsWith(folder, StringComparison.OrdinalIgnoreCase))) continue;
                
                var guidMapper = new GuidMapper
                {
                    Guid = guid,
                    Path = path
                };
                mapperList.Add(guidMapper);
            }
            
            var savePath = EditorUtility.SaveFilePanel("Save GUID Mapper", Application.dataPath, $"{exportFor} - guidMapper", "json");
            if (!string.IsNullOrEmpty(savePath))
            {
                JsonFileSystem.Write(mapperList, savePath);
            }
            
            Debug.Log($"Successfully exported {mapperList.Count} {exportFor} GUIDs");
        }
        
        private static (string searchPattern, string extension) GetSearchPattern(ExportFor exportFor)
        {
            return exportFor switch
            {
                ExportFor.Script => ("t:MonoScript", "cs"),
                ExportFor.Scene => ("t:SceneAsset", "unity"),
                ExportFor.Prefab => ("t:Prefab", "prefab"),
                ExportFor.ScriptableObject => ("t:ScriptableObject", "asset"),
                ExportFor.All => ("", "*"),
                _ => throw new ArgumentOutOfRangeException(nameof(exportFor), exportFor, null)
            };
        }
        
        [MenuItem("Tools/Exporter/GUID Exporter/Export All GUIDs")]
        public static void ExportAllGuids()
        {
            BulkExport();
        }

        public static void BulkExport(string savePath = null)
        {
            var typeToGuidMapper = new Dictionary<Type, List<GuidMapper>>();
            
            var settings = ProjectExporterSettings.GetOrCreateSettings();
            var folderToIgnore = settings.FoldersToIgnore;
            var assets = AssetDatabase.FindAssets("", new[] { "Assets" });
            foreach (var guid in assets)
            {
                var path = AssetDatabase.GUIDToAssetPath(guid);
                
                if (folderToIgnore.Any(folder => path.StartsWith(folder, StringComparison.OrdinalIgnoreCase))) continue;
                
                var extension = Path.GetExtension(path);
                var type = AssetDatabase.GetMainAssetTypeAtPath(path);
                if (type == null || extension == null) continue;

                if (type == typeof(DefaultAsset) && File.GetAttributes(path).HasFlag(FileAttributes.Directory))
                {
                    continue;
                }
                if (type.IsSubclassOf(typeof(ScriptableObject)) && extension == ".asset")
                {
                    type = typeof(ScriptableObject);
                }

                if (type == typeof(GameObject))
                {
                    if (extension == ".prefab")
                    {
                        type = typeof(Prefab);
                    }
                    else if (CommonModelExtensions.Contains(extension.ToLower())) 
                    {
                        type = typeof(Model);
                    }
                }

                var guidMapper = new GuidMapper
                {
                    Guid = guid,
                    Path = path
                };
                
                if (!typeToGuidMapper.ContainsKey(type))
                {
                    typeToGuidMapper[type] = new List<GuidMapper>();
                }
                
                typeToGuidMapper[type].Add(guidMapper);
            }
            
            savePath ??= EditorUtility.SaveFilePanel("Save GUID Mappers", Application.dataPath, "guidMappers", "json");
            if (string.IsNullOrEmpty(savePath))
            {
                Debug.LogWarning("GUID Mappers not exported");
                return;
            }
            
            foreach (var (type, guidMappers) in typeToGuidMapper)
            {
                var friendlyName = type.Name.Split('.').Last();
                var fileName = $"{friendlyName} - guidMapper.json";
                var dirName = Path.HasExtension(savePath) ? Path.GetDirectoryName(savePath) : savePath;
                var filePath = Path.Combine(dirName ?? Application.dataPath, fileName);
                JsonFileSystem.Write(guidMappers, filePath);
            }
            Debug.Log($"Exported {typeToGuidMapper.Count} GUID Mappers");
        }
        
        private class Prefab { }

        private class Model { }
    }
}