using TFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.IO;
using System.Text;

namespace TFramework
{
    [CustomEditor(typeof(UIBehaviour))]
    public class UIBehaviourInspector : TEditor
    {
        SerializedProperty m_id;
        SerializedProperty enableAnim;
        SerializedProperty m_uiAnimType;
        SerializedProperty isScriptUse;
        SerializedProperty variableInfos;
        SerializedProperty parnetPanel;
        Component[] behaviours;
        ReorderableList variableList;
        SerializedProperty useResInfos;
        ReorderableList useResList;

        List<string> anims = new List<string>();
        int select = 0;

        List<string> parentPanles = new List<string>();
        int selectParent = -1;

        Dictionary<string, string> scriptPathDic = new Dictionary<string, string>();

        string scriptText;

        const string INITFLGS = "base.OnInit();";

        private void OnEnable()
        {
            m_id = serializedObject.FindProperty("m_id");
            enableAnim = serializedObject.FindProperty("enableAnim");
            m_uiAnimType = serializedObject.FindProperty("m_uiAnimType");
            isScriptUse = serializedObject.FindProperty("isScriptUse");
            variableInfos = serializedObject.FindProperty("variableInfos");
            parnetPanel = serializedObject.FindProperty("parnetPanel");
            useResInfos = serializedObject.FindProperty("useResInfos");

            if (string.IsNullOrEmpty(m_id.stringValue))
            {
                (target as UIBehaviour).ResetID();
            }
            anims.Add("None");
            foreach (var item in GlobalTool.GetTypesInRunTimeAssemblies(type =>
            (type.IsSubclassOf(typeof(UIAnimBase)) || (type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(UIAnimBase)))
            && type.IsClass && !type.IsAbstract && type.Name != typeof(UIAnimBase).Name))
            {
                anims.Add(item.FullName);
            }

            behaviours = (target as UIBehaviour).GetComponents<Component>();

            foreach (var item in GlobalTool.GetTypesInRunTimeAssemblies(type =>
            (type.IsSubclassOf(typeof(BasePanel)) || (type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(BasePanel)))
            && type.IsClass && !type.IsAbstract && type.Name != typeof(BasePanel).Name))
            {
                parentPanles.Add(item.FullName);
                string[] guids = AssetDatabase.FindAssets(item.Name + ".Designer t:Script");
                if (guids.Length <= 0)
                    guids = AssetDatabase.FindAssets(item.Name + " t:Script");

                if (guids.Length > 0)
                {
                    string scriptPath = AssetDatabase.GUIDToAssetPath(guids[0]);
                    if (!scriptPathDic.ContainsKey(item.FullName))
                        scriptPathDic.Add(item.FullName, scriptPath);
                }
            }

            variableList = new ReorderableList(serializedObject, variableInfos, false, true, true, true);

            variableList.drawHeaderCallback = (rect) =>
            {
                GUI.Label(rect, "绑定组件");
            };

            variableList.drawElementCallback = (rect, index, isActive, isFocused) =>
             {
                 SerializedProperty property = variableInfos.GetArrayElementAtIndex(index);
                 SerializedProperty variableName = property.FindPropertyRelative("variableName");
                 SerializedProperty compentType = property.FindPropertyRelative("compentType");
                 float width = rect.width / 2;
                 rect.width = 63;
                 GUI.Label(rect, "变量名：");
                 rect.x += 63;
                 rect.width = width - 63;
                 string newName = EditorGUI.TextField(rect, variableName.stringValue);
                 if (newName != variableName.stringValue)
                 {
                     if (!string.IsNullOrEmpty(compentType.stringValue))
                     {
                         int indexPos = scriptText.IndexOf($"private {compentType.stringValue} {variableName.stringValue};");
                         if (indexPos == -1)
                         {
                             indexPos = scriptText.IndexOf("#endregion");
                             scriptText = scriptText.Insert(indexPos, $"private {compentType.stringValue} {newName};\n    ");
                         }
                         else
                         {
                             scriptText = scriptText.Replace($"private {compentType.stringValue} {variableName.stringValue};", $"private {compentType.stringValue} {newName};");
                         }

                         int initPos = scriptText.IndexOf($" {variableName.stringValue} = GetComponentInUIID<{compentType.stringValue}>(\"{m_id.stringValue}\");");
                         if (initPos == -1)
                         {
                             initPos = scriptText.IndexOf(INITFLGS) + INITFLGS.Length;
                             scriptText = scriptText.Insert(initPos, $"\n        {newName} = GetComponentInUIID<{compentType.stringValue}>(\"{m_id.stringValue}\");");
                         }
                         else
                         {
                             scriptText = scriptText.Replace($" {variableName.stringValue} = GetComponentInUIID<{compentType.stringValue}>(\"{m_id.stringValue}\");",
                                 $" {newName} = GetComponentInUIID<{compentType.stringValue}>(\"{m_id.stringValue}\");");
                         }

                         string path = Application.dataPath.Remove(Application.dataPath.LastIndexOf("Assets"));
                         path += scriptPathDic[parnetPanel.stringValue];
                         StreamWriter baseWriter = new StreamWriter(path, false, UTF8Encoding.UTF8);
                         baseWriter.Write(scriptText);
                         baseWriter.Close();

                         AssetDatabase.Refresh();
                     }
                     variableName.stringValue = newName;
                 }
                 rect.x += rect.width + 3;
                 rect.width = 80;
                 GUI.Label(rect, "组件类型:");
                 GenericMenu menu = new GenericMenu();
                 foreach (var item in behaviours)
                 {
                     menu.AddItem(new GUIContent(item.GetType().Name), compentType.stringValue == item.GetType().Name, () =>
                     {
                         serializedObject.Update();
                         string oldType = compentType.stringValue;
                         compentType.stringValue = item.GetType().Name;
                         if (!variableName.stringValue.Contains(compentType.stringValue))
                         {
                             variableName.stringValue += compentType.stringValue;
                         }

                         int index = scriptText.IndexOf($"private {oldType} {variableName.stringValue};");
                         if (index == -1)
                         {
                             index = scriptText.IndexOf("#endregion");
                             scriptText = scriptText.Insert(index, $"private {compentType.stringValue} {variableName.stringValue};\n    ");
                         }
                         else
                         {
                             scriptText = scriptText.Replace($"private {oldType} {variableName.stringValue};", $"private {compentType.stringValue} {variableName.stringValue};");
                         }

                         int initPos = scriptText.IndexOf($" {variableName.stringValue} = GetComponentInUIID<{oldType}>(\"{m_id.stringValue}\");");
                         if (initPos == -1)
                         {
                             initPos = scriptText.IndexOf(INITFLGS) + INITFLGS.Length;
                             scriptText = scriptText.Insert(initPos, $"\n        {variableName.stringValue} = GetComponentInUIID<{compentType.stringValue}>(\"{m_id.stringValue}\");");
                         }
                         else
                         {
                             scriptText = scriptText.Replace($" {variableName.stringValue} = GetComponentInUIID<{oldType}>(\"{m_id.stringValue}\");",
                                 $" {variableName.stringValue} = GetComponentInUIID<{compentType.stringValue}>(\"{m_id.stringValue}\");");
                         }
                         if (!scriptText.Contains($"using {item.GetType().Namespace};"))
                         {
                             scriptText = scriptText.Insert(0, $"using {item.GetType().Namespace};\n");
                         }

                         string path = Application.dataPath.Remove(Application.dataPath.LastIndexOf("Assets"));
                         path += scriptPathDic[parnetPanel.stringValue];
                         StreamWriter baseWriter = new StreamWriter(path, false, UTF8Encoding.UTF8);
                         baseWriter.Write(scriptText);
                         baseWriter.Close();
                         AssetDatabase.Refresh();
                         serializedObject.ApplyModifiedProperties();
                     });
                 }
                 rect.x += 63;
                 rect.width = width - 80;
                 if (GUI.Button(rect, compentType.stringValue))
                 {
                     menu.ShowAsContext();
                 }
             };

            variableList.multiSelect = false;
            variableList.onAddCallback = (list) =>
            {
                serializedObject.Update();

                int newIndex = list.serializedProperty.arraySize;
                list.serializedProperty.InsertArrayElementAtIndex(newIndex);

                list.index = newIndex;

                SerializedProperty newItem = list.serializedProperty.GetArrayElementAtIndex(newIndex);
                newItem.FindPropertyRelative("variableName").stringValue = (target as UIBehaviour).gameObject.name + "_";
                newItem.FindPropertyRelative("compentType").stringValue = "UIBehaviour";
                serializedObject.ApplyModifiedProperties();
            };
            variableList.onRemoveCallback = (list) =>
            {
                SerializedProperty property = variableInfos.GetArrayElementAtIndex(list.index);
                SerializedProperty variableName = property.FindPropertyRelative("variableName");
                SerializedProperty compentType = property.FindPropertyRelative("compentType");
                int index = scriptText.IndexOf($"private {compentType.stringValue} {variableName.stringValue};");
                if (index != -1)
                    scriptText = scriptText.Replace($"private {compentType.stringValue} {variableName.stringValue};\n    ", "");

                int initPos = scriptText.IndexOf($" {variableName.stringValue} = GetComponentInUIID<{compentType.stringValue}>(\"{m_id.stringValue}\");");
                if (initPos != -1)
                {
                    scriptText = scriptText.Replace($"\n        {variableName.stringValue} = GetComponentInUIID<{compentType.stringValue}>(\"{m_id.stringValue}\");", "");
                }

                string path = Application.dataPath.Remove(Application.dataPath.LastIndexOf("Assets"));
                path += scriptPathDic[parnetPanel.stringValue];
                StreamWriter baseWriter = new StreamWriter(path, false, UTF8Encoding.UTF8);
                baseWriter.Write(scriptText);
                baseWriter.Close();
                AssetDatabase.Refresh();
                ReorderableList.defaultBehaviours.DoRemoveButton(list);
            };

            useResList = new ReorderableList(serializedObject, useResInfos, false, true, true, true);
            useResList.drawHeaderCallback = rect =>
            {
                GUI.Label(rect, "使用资源列表");
            };
            useResList.drawElementCallback = (rect, index, isActive, isFocused) =>
            {
                SerializedProperty property = useResInfos.GetArrayElementAtIndex(index);
                SerializedProperty resObj = property.FindPropertyRelative("resObj");
                SerializedProperty resName = property.FindPropertyRelative("resName");
                float width = rect.width / 2;
                rect.width = 63;
                GUI.Label(rect, "资源名：");
                rect.x += 63;
                rect.width = width - 63;
                resName.stringValue = EditorGUI.TextField(rect, resName.stringValue);
                
                rect.x += rect.width + 3;
                rect.width = 43;
                GUI.Label(rect, "资源：");
                rect.x += 43;
                rect.width = width - 40;
                resObj.objectReferenceValue = EditorGUI.ObjectField(rect, resObj.objectReferenceValue, typeof(Object), true);
            };


            if (!string.IsNullOrEmpty(parnetPanel.stringValue))
                scriptText = AssetDatabase.LoadAssetAtPath<TextAsset>(scriptPathDic[parnetPanel.stringValue]).text;
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            using (new EditorGUILayout.HorizontalScope())
            {
                GUI.enabled = false;
                EditorGUILayout.PropertyField(m_id, new GUIContent("ID"));
                GUI.enabled = true;
                if(GUILayout.Button("重置",GUILayout.ExpandWidth(false)))
                {
                    (target as UIBehaviour).ResetID();
                }
                DrawGUILayoutCopyButton(m_id.stringValue);
            }
            EditorGUILayout.PropertyField(enableAnim, new GUIContent("启用动画"));
            if(enableAnim.boolValue)
            {
                select = anims.IndexOf(m_uiAnimType.stringValue);
                select = select == -1 ? 0 : select;
                int newSelect = EditorGUILayout.Popup("动画类型", select, anims.ToArray());
                if(newSelect!=select)
                {
                    m_uiAnimType.stringValue = anims[newSelect];
                    select = newSelect;
                }
            }

            EditorGUILayout.PropertyField(isScriptUse, new GUIContent("绑定脚本"));
            if(isScriptUse.boolValue)
            {
                using(new EditorGUILayout.VerticalScope("Box"))
                {
                    selectParent = parentPanles.IndexOf(parnetPanel.stringValue);
                    //selectParent = selectParent == -1 ? 0 : selectParent;
                    int newParent = EditorGUILayout.Popup("绑定到面板", selectParent, parentPanles.ToArray());
                    if (newParent != selectParent)
                    {
                        parnetPanel.stringValue = parentPanles[newParent];
                        selectParent = newParent;
                        scriptText = string.Empty;
                        scriptText = AssetDatabase.LoadAssetAtPath<TextAsset>(scriptPathDic[parnetPanel.stringValue]).text;
                    }
                    variableList.DoLayoutList();
                }
            }
            useResList.DoLayoutList();
            serializedObject.ApplyModifiedProperties();
        }
    }
}
