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

namespace Assets.Source.Editor
{
    public class SOCreatorWindow : EditorWindow
    {
        private List<Type> _soTypes = new List<Type>();
        private Vector2 _scrollPos;
        private string _namespaceFilter = "Assets.Source";
        private string _nameFilter = "";
        private string _createPath = "Assets";
        private GUIStyle _buttonStyle;

        [MenuItem("Tools/SOCreator")]
        public static void ShowWindow()
        {
            GetWindow<SOCreatorWindow>(utility: true, title: "SOCreator");
        }

        void OnEnable()
        {
            _buttonStyle = new GUIStyle(EditorStyles.toolbarButton) { richText = true, alignment = TextAnchor.MiddleLeft };
            Refresh();
        }

        void OnGUI()
        {
            _namespaceFilter = EditorGUILayout.TextField("Namespace filter", _namespaceFilter);
            _nameFilter = EditorGUILayout.TextField("Name filter", _nameFilter);
            _createPath = EditorGUILayout.TextField("Create path", _createPath);
            if (GUILayout.Button("Refresh"))
                Refresh();

            _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos);
            foreach (var soType in _soTypes)
            {
                if (!string.IsNullOrEmpty(_namespaceFilter) && soType.Namespace != null && !soType.Namespace.Contains(_namespaceFilter))
                    continue;
                if (!string.IsNullOrEmpty(_nameFilter) && !soType.Name.ToLower().Contains(_nameFilter.ToLower()))
                    continue;
                var nameText = soType.Name.SetColorTag("green");
                if (!string.IsNullOrEmpty(soType.Namespace))
                    nameText = (soType.Namespace + ".").SetColorTag("grey") + nameText;

                if (GUILayout.Button(nameText, _buttonStyle))
                    CreateSO(soType);
            }
            EditorGUILayout.EndScrollView();
        }

        private void Refresh()
        {
            var assembly = Assembly.Load(new AssemblyName("Assembly-CSharp"));
            _soTypes = (from t in assembly.GetTypes()
                        where t.IsSubclassOf(typeof(ScriptableObject))
                        where !t.IsSubclassOf(typeof(EditorWindow))
                        where !t.IsAbstract
                        where !t.IsGenericType
                        select t).ToList();
        }

        private void CreateSO(Type type)
        {
            CreateAsset(type,
                path: _createPath + "/",
                name: type.Name,
                unique: true);
        }

        public static void CreateAsset(Type type, string path, string name, bool unique)
        {
            var asset = ScriptableObject.CreateInstance(type);

            var assetPathAndName = path + name + ".asset";
            if (unique)
                assetPathAndName = AssetDatabase.GenerateUniqueAssetPath(assetPathAndName);

            CreateOrReplaceAsset(type, asset, assetPathAndName);

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        public static void CreateOrReplaceAsset(Type type, ScriptableObject asset, string path)
        {
            var existingAsset = AssetDatabase.LoadAssetAtPath(path, type);

            if (existingAsset == null)
            {
                AssetDatabase.CreateAsset(asset, path);
                existingAsset = asset;
            }
            else
            {
                EditorUtility.CopySerialized(asset, existingAsset);
            }
        }
    }
}
