using TFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Text;
using System.IO;
using System;
using System.Reflection;
using System.Linq;

namespace TFramework
{
    public class CreateScriptEdit : EditorWindow
    {
        private string _scriptName;

        string ScriptName
        {
            get => _scriptName;
            set
            {
                if (_scriptName == value) return;
                _scriptName = value;
                WritScript();
            }
        }

        private bool _isUserNamespace;
        bool IsUserNamespace
        {
            get => _isUserNamespace;
            set
            {
                if (_isUserNamespace == value) return;
                _isUserNamespace = value;
                WritScript();
            }
        }

        private string _namespce;
        string Namespce
        {
            get => _namespce;
            set
            {
                if (_namespce == value) return;
                _namespce = value;
                WritScript();
            }
        }
        private bool _isInheritMonon;
        bool IsInheritMono
        {
            get => _isInheritMonon;
            set
            {
                if (_isInheritMonon == value) return;
                _isInheritMonon = value;
                WritScript();
            }
        }

        private string _scriptDes;

        string ScriptDes
        {
            get => _scriptDes;
            set
            {
                if (_scriptDes == value) return;
                _scriptDes = value;
                WritScript();
            }
        }

        [SerializeField]
        private StringBuilder _script = new StringBuilder();

        [SerializeField]
        private DesTempData _tempData;

        [SerializeField]
        private UserData _userData;

        [SerializeField]
        private Dictionary<string, string> desFiledDic = new Dictionary<string, string>();
        [SerializeField]
        private List<string> _keys = new List<string>();

        const string TEMPDATAPATH = "Assets/TFramework/Editor/CreateScript/DesTemp/DesTempData.asset";
        const string USERDATAPATH = "Assets/TFramework/Editor/UserInfo/UserData.asset";
        
        private Dictionary<string, string> classTypeDic = new Dictionary<string, string>
        {
            {"类","class" },
            {"结构体","struct" },
            {"枚举","enum" },
            {"接口","interface" }
        };

        private string classType = string.Empty;

        string ClassType
        {
            get => classType;
            set
            {
                if (classType == value) return;
                classType = value;
                IsInheritMono = (IsInheritMono && classType == "类");
                InheritClass = "None";
                GetAllType();
                WritScript();
            }
        }

        DesTempData TempData
        {
            get
            {
                _tempData = _tempData ??
                    AssetDatabase.LoadAssetAtPath<DesTempData>(TEMPDATAPATH);
                if (_tempData == null)
                    CreateTempData();
                return _tempData;
            }
        }

        UserData User
        {
            get
            {
                _userData = _userData ?? AssetDatabase.LoadAssetAtPath<UserData>(USERDATAPATH);
                if (_userData == null)
                    CreateUserData();
                return _userData;
            }
        }

        private void CreateUserData()
        {
            _userData = CreateInstance<UserData>();
            AssetDatabase.CreateAsset(_userData, USERDATAPATH);
            AssetDatabase.Refresh();
            _userData = AssetDatabase.LoadAssetAtPath<UserData>(USERDATAPATH);
        }

        List<string> selecteMenu = new List<string>();

        int _selecteTemp = 0;
        int SelecteTemp
        {
            get => _selecteTemp;
            set
            {
                if (_selecteTemp == value) return;
                _selecteTemp = value;
                FiedGather();
                WritScript();
            }
        }

        GenericMenu classTypeMenu;

        GenericMenu inheritClassMenu;

        GenericMenu citeMenu;

        List<Type> _allType = new List<Type>();

        private string _inheritClass;

        string InheritClass
        {
            get => _inheritClass;
            set
            {
                if (_inheritClass == value) return;
                _inheritClass = value;
                WritScript();
            }
        }

        private static readonly HashSet<Type> IntegerTypes = new HashSet<Type>
    {
        typeof(byte),
        typeof(sbyte),
        typeof(short),
        typeof(ushort),
        typeof(int),
        typeof(uint),
        typeof(long),
        typeof(ulong)
    };

        private static HashSet<string> Cites = new HashSet<string>();

        public static void OpenWin()
        {
            CreateScriptEdit win = GetWindow<CreateScriptEdit>();
            win.minSize = new Vector2(450, 200);
            win.titleContent.text = "创建脚本";
            win.titleContent.image = EditorGUIUtility.IconContent("cs Script Icon").image;
        }

        private void OnEnable()
        {
            RefreshTemp();

            Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var ab in assemblys)
                foreach (var type in ab.GetTypes())
                    if (type.IsPublic)
                        _allType.Add(type);

            GetAllCite();
            IsInheritMono = true;
            IsUserNamespace = true;
            ClassType = "类";
            InheritClass = "None";

            GetClassType();
        }

        void GetClassType()
        {
            classTypeMenu = new GenericMenu();
            foreach (var item in classTypeDic)
            {
                classTypeMenu.AddItem(new GUIContent(item.Key), ClassType.Equals(item.Key), () =>
                {
                    ClassType = item.Key;
                });
            }
        }

        void GetAllType()
        {
            inheritClassMenu = new GenericMenu();
            inheritClassMenu.AddItem(new GUIContent("None"), InheritClass.Equals("None"), () => InheritClass = "None");
            foreach (var type in _allType)
            {
                if(ClassType=="类"&&(type.IsInterface || type.IsClass))
                    inheritClassMenu.AddItem(new GUIContent(type.FullName.Replace('.', '/')), InheritClass.Equals(type.FullName),
                        () => InheritClass = type.FullName);
                else if((ClassType == "接口"|| ClassType == "结构体")&& type.IsInterface)
                    inheritClassMenu.AddItem(new GUIContent(type.FullName.Replace('.', '/')), InheritClass.Equals(type.FullName),
                        () => InheritClass = type.FullName);
                else if(ClassType == "枚举"&& IntegerTypes.Contains(type))
                    inheritClassMenu.AddItem(new GUIContent(type.FullName.Replace('.', '/')), InheritClass.Equals(type.FullName),
                        () => InheritClass = type.FullName);
            }
        }

        void GetAllCite()
        {
            citeMenu = new GenericMenu();
            
            foreach (var type in _allType.GroupBy(p => p.Namespace))
            {
                if (string.IsNullOrEmpty(type.Key)) continue;
                bool isG = Cites.Contains(type.Key);
                citeMenu.AddItem(new GUIContent(type.Key.Replace('.', '/')+'#'), isG , () =>
                {
                    if (Cites.Contains(type.Key))
                        Cites.Remove(type.Key);
                    else
                        Cites.Add(type.Key);
                    WritScript();
                });
            }
        }

        void RefreshTemp()
        {
            selecteMenu.Clear();
            selecteMenu.Add("None");
            TempData.desTempInfos.ForEach(p =>
            {
                selecteMenu.Add(p.m_name);
            });
        }
        private void CreateTempData()
        {
            _tempData = ScriptableObject.CreateInstance<DesTempData>();
            AssetDatabase.CreateAsset(_tempData, TEMPDATAPATH);
            AssetDatabase.Refresh();
            _tempData = AssetDatabase.LoadAssetAtPath<DesTempData>(TEMPDATAPATH);
        }


        void FiedGather()
        {
            ScriptDes = string.Empty;
            desFiledDic.Clear();
            _keys.Clear();
            if (SelecteTemp <= 0) return;
            
            string str = TempData.desTempInfos.Find(p => p.m_name == selecteMenu[SelecteTemp]).m_des;
            ScriptDes = str.Replace("+", "");
            str = str.Remove(0,str.IndexOf("+"));
            str = str.Remove(str.LastIndexOf("："));
            //Debug.Log(str);
            string[] strs = str.Split("\n");
            string key = string.Empty;
            for (int i = 0; i < strs.Length; i++)
            {
                key = string.Empty;
                for (int j = 0; j < strs[i].Length; j++)
                {
                    if (strs[i][j] != '+'&& strs[i][j] != '：' && strs[i][j] != ':'&&strs[i][j]!=' ')
                        key += strs[i][j];
                    if (strs[i][j] == '：'|| strs[i][j] == ':')
                        break;
                }
                if(!string.IsNullOrEmpty(key))
                {
                    desFiledDic.Add(key, "");
                    _keys.Add(key);
                }
            }
        }

        private void OnGUI()
        {
            using(new EditorGUILayout.HorizontalScope())
            {
                DrawLeft();
                DrawRight();
            }
        }

        void DrawLeft()
        {
            using (new EditorGUILayout.VerticalScope(GUILayout.Width(200)))
            {
                using (new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label("脚本名");
                    ScriptName = EditorGUILayout.TextField(ScriptName);
                }

                using(new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label("脚本类型");
                    if(GUILayout.Button(classType,EditorStyles.popup))
                    {
                        GetClassType();
                        classTypeMenu.ShowAsContext();
                    }
                }

                GUI.enabled = classType == "类";
                using (new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label("继承Mono");
                    IsInheritMono = EditorGUILayout.Toggle(IsInheritMono);
                }
                GUI.enabled = true;

                using (new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label("脚本引用");
                    if (GUILayout.Button("管理引用", EditorStyles.popup))
                    {
                        GetAllCite();
                        citeMenu.ShowAsContext();
                    }
                }

                if (!IsInheritMono)
                {
                    using (new EditorGUILayout.HorizontalScope())
                    {
                        GUILayout.Label("继承父类");
                        if (GUILayout.Button(_inheritClass, EditorStyles.popup))
                        {
                            GetAllType();
                            inheritClassMenu.ShowAsContext();
                        }
                    }
                }
                using (new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label("使用命名空间");
                    IsUserNamespace = EditorGUILayout.Toggle(IsUserNamespace);
                }
                if (IsUserNamespace)
                {
                    using (new EditorGUILayout.HorizontalScope())
                    {
                        GUILayout.Label("命名空间");
                        Namespce = EditorGUILayout.TextField(Namespce);
                    }
                }
                using (new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label("脚本描述");
                    SelecteTemp = EditorGUILayout.Popup(SelecteTemp,selecteMenu.ToArray());
                    if(GUILayout.Button("新建"))
                    {
                        NewDesTemp.Open(TempData, RefreshTemp);
                    }
                }
                if(_keys.Count>0)
                {
                    for (int i = 0; i < _keys.Count; i++)
                    {
                        string value = string.Empty; 
                        int j = i;
                        using (new EditorGUILayout.HorizontalScope())
                        {
                            GUILayout.Label(_keys[i],GUILayout.ExpandWidth(false));
                            value = EditorGUILayout.TextField(desFiledDic[_keys[i]]);
                            switch (_keys[i])
                            {
                                case "文件":
                                    value = ScriptName+".cs";
                                    break;
                                case "日期":
                                    value = DateTime.Now.ToString("U");
                                    break;
                                case "UnityVersion":
                                case "Unity版本":
                                    value = Application.unityVersion;
                                    break;
                                case "作者":
                                    value = User.m_name;
                                    break;
                                case "邮箱":
                                    value = User.m_email;
                                    break;
                                default:
                                    break;
                            }
                            if(value != desFiledDic[_keys[j]])
                            {
                                ScriptDes = ScriptDes.Replace($"?{j}{desFiledDic[_keys[j]]}", $"?{j}{value}");
                                desFiledDic[_keys[j]] = value;
                            }
                        }
                    }
                }
                GUI.color = Color.green;
                if (GUILayout.Button("创建"))
                {
                    CreateScript();
                }
                GUI.color = Color.white;
            }
        }

        void DrawRight()
        {
            using (new EditorGUILayout.VerticalScope("Box"))
            {
                EditorGUILayout.LabelField("预览:");
                GUI.enabled = false;
                EditorGUILayout.TextArea(_script.ToString());
                GUI.enabled = true;
            }
        }

        private void WritScript()
        {
            _script.Clear();
            if (SelecteTemp > 0)
            {
                string des = ScriptDes;
                for (int i = 0; i < _keys.Count; i++)
                {
                    des = des.Replace($"?{i}", "");
                }
                _script.Append(des);
                _script.Append("\n");
            }
            //if (_isInheritMonon)
            //{
            //    _script.Append("using System.Collections;\n");
            //    _script.Append("using UnityEngine;\n");
            //}
            //_script.Append("using System.Collections.Generic;\n");
            foreach (var item in Cites)
            {
                _script.Append($"using {item};\n");
            }
            if (_isUserNamespace)
            {
                _script.Append($"namespace {_namespce}\n");
                _script.Append("{\n");
            }
            _script.Append($"{(_isUserNamespace ? "    " : "")}public {(classTypeDic.ContainsKey(classType)? classTypeDic[classType]:"class")} {_scriptName} {(_isInheritMonon ? ": MonoBehaviour" : (InheritClass=="None"?"":$": {InheritClass}")) }\n");
            _script.Append(_isUserNamespace ? "    " : "");
            _script.Append("{\n");
            _script.Append(_isUserNamespace ? "    " : "");
            _script.Append("}\n");
            if (_isUserNamespace)
            {
                _script.Append("}");
            }
        }

        private void CreateScript()
        {
            if (_script.Length < 0) return;
            string fullName = "Assets";
            UnityEngine.Object[] objects = Selection.GetFiltered<DefaultAsset>(SelectionMode.Assets);
            if (objects.Length > 0)
                fullName = AssetDatabase.GetAssetPath(objects[0]);
            fullName += $"/{_scriptName}.cs";
            string pathName = Application.dataPath.Remove(Application.dataPath.LastIndexOf("/")+1) + fullName;
            StreamWriter writer = new StreamWriter(pathName, false, UTF8Encoding.UTF8);
            writer.Write(_script.ToString());
            writer.Close();

            AssetDatabase.ImportAsset(fullName);
            MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(fullName);
            AssetDatabase.OpenAsset(script);
            AssetDatabase.Refresh();
            Close();
        }
    }

    public class NewDesTemp:EditorWindow
    {
        static DesTempData _tempData;
        static TAction onSave;

        DesTempInfo tempInfo = new DesTempInfo();

        bool isCanSave = true;

        public static void Open(DesTempData tempData,TAction action)
        {
            NewDesTemp win = GetWindow<NewDesTemp>();
            win.minSize = new Vector2(300, 300);
            _tempData = tempData;
            win.titleContent.text = "脚本描述模版";
            onSave = action;
            win.Show();
        }

        private void OnGUI()
        {
            using(new EditorGUILayout.HorizontalScope())
            {
                GUILayout.Label("名称", GUILayout.ExpandWidth(false));
                isCanSave = true;
                tempInfo.m_name = EditorGUILayout.TextField(tempInfo.m_name);
                if(_tempData.desTempInfos.Find(p=>p.m_name==tempInfo.m_name)!=null)
                {
                    EditorGUILayout.HelpBox("存在同名模版！请更换名称", MessageType.Error);
                    isCanSave = false;
                }
            }
            using (new EditorGUILayout.HorizontalScope())
            {
                GUILayout.Label("描述",GUILayout.ExpandWidth(false));
                tempInfo.m_des = EditorGUILayout.TextArea(tempInfo.m_des);
            }
            if(GUILayout.Button("保存"))
            {
                if(!string.IsNullOrEmpty(tempInfo.m_name)&&!string.IsNullOrEmpty(tempInfo.m_des)&&isCanSave)
                {
                    _tempData.desTempInfos.Add(tempInfo);
                    onSave?.Invoke();
                    EditorUtility.SetDirty(_tempData);
                    AssetDatabase.SaveAssets();
                    Close();
                }
            }
        }
    }
}
