using System.IO;
using System.Text;
using JLGames.RocketDriver.Actions.Utils;
using UnityEditor;
using UnityEngine;

namespace JLGames.RocketDriver.Editor.Windows.Tools
{
    public class WinFindLayer : EditorWindow
    {
        class Context
        {
            public string CheckPath = "Assets";
            public string SavePath = "Editor/LayerSearch.log";
            public int SearchLayer = -1;
            public int Replacelayer = -1;
            public bool Running;
            public int ProcessIndex;
            public int ProcessLen;

            public bool SearchValid => SearchLayer != -1;
            public bool ReplaceValid => SearchValid && Replacelayer != -1;

            public string AbsSavePath => UnityPathUtil.CombineUnityPath(Application.dataPath, SavePath);

            public float ProcessPercent => (float)ProcessIndex / ProcessLen;
        }

        private static Context m_Context = new Context();

        string m_CheckLayer;
        string m_ReplaceLayer;
        bool m_Toggle;

        private void OnGUI()
        {
            GUILayout.BeginHorizontal();
            m_Toggle = EditorGUILayout.BeginToggleGroup("选择路径", m_Toggle);
            if (Selection.assetGUIDs.Length > 0 && !m_Context.Running && m_Toggle)
            {
                var selectPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
                m_Context.CheckPath = selectPath;
            }

            EditorGUILayout.EndToggleGroup();
            GUILayout.EndHorizontal();
            GUILayout.Space(10);

            GUILayout.BeginHorizontal();
            m_Context.CheckPath = EditorGUILayout.TextField("输入当前查找/替换的路径:", m_Context.CheckPath);
            GUILayout.EndHorizontal();
            GUILayout.Space(10);

            GUILayout.BeginHorizontal();
            m_CheckLayer = EditorGUILayout.TextField("输入当前查找的layer层:", m_CheckLayer);
            GUILayout.EndHorizontal();
            GUILayout.Space(10);

            GUILayout.BeginHorizontal();
            m_ReplaceLayer = EditorGUILayout.TextField("输入替换的layer层:", m_ReplaceLayer);
            GUILayout.EndHorizontal();
            GUILayout.Space(10);

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("开始查找", "buttonleft", GUILayout.Width(250), GUILayout.Height(50)))
            {
                m_Context.SearchLayer = LayerMask.NameToLayer(m_CheckLayer);
                if (!m_Context.SearchValid)
                {
                    m_CheckLayer = "";
                    EditorUtility.DisplayDialog("Find Layer", $"Undefined Layer Name:'{m_CheckLayer}'", "Ok");
                }

                else
                {
                    CheckAllGameObjectByLayer();
                }
            }

            GUILayout.EndHorizontal();
            GUILayout.Space(10);

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("开始替换", "buttonleft", GUILayout.Width(250), GUILayout.Height(50)))
            {
                m_Context.SearchLayer = LayerMask.NameToLayer(m_CheckLayer);
                m_Context.Replacelayer = LayerMask.NameToLayer(m_ReplaceLayer);
                if (!m_Context.ReplaceValid)
                {
                    m_CheckLayer = "";
                    if (!m_Context.SearchValid)
                        EditorUtility.DisplayDialog("Replace Layer", $"Undefined Layer Name:'{m_CheckLayer}'", "Ok");
                    else
                        EditorUtility.DisplayDialog("Replace Layer", $"Undefined Layer Name:'{m_ReplaceLayer}'", "Ok");
                }
                else
                {
                    ReplaceAllGameObjectLayer();
                }
            }

            GUILayout.EndHorizontal();
            GUILayout.Space(10);
        }

        private void CheckAllGameObjectByLayer()
        {
            // 清理输出文件保存路径
            if (File.Exists(m_Context.AbsSavePath))
                File.Delete(m_Context.AbsSavePath);

            //查找checkPath路径下的所有文件路径
            var allPath = Directory.GetFiles(m_Context.CheckPath, "*.prefab", SearchOption.AllDirectories);
            if (allPath.Length == 0)
            {
                EditorUtility.DisplayDialog("Find Layer", $"No Prefab in Path: '{m_Context.CheckPath}'", "Ok");
                return;
            }

            m_Context.Running = true;
            m_Context.ProcessIndex = 0;
            m_Context.ProcessLen = allPath.Length;
            //把预制体和预制体里面的子物体写入到文件LayerSetting.text中
            using (var fs = new FileStream(m_Context.AbsSavePath, FileMode.OpenOrCreate))
            {
                var sw = new StreamWriter(new BufferedStream(fs), Encoding.UTF8);
                var allStr = "";
                for (var i = 0; i < allPath.Length; i++)
                {
                    if (File.Exists(allPath[i]))
                    {
                        //通过路径获取游戏obj
                        var obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
                        if (obj == null) continue;
                        if (obj.layer == m_Context.SearchLayer)
                        {
                            allStr += $"{allPath[i]}\r\n";
                            IterationAllGameObject(obj.transform, obj.name, ref allStr);
                            allStr += "\r\n";
                        }
                        else
                        {
                            IterationAllGameObject(obj.transform, obj.name, ref allStr);
                        }
                    }

                    m_Context.ProcessIndex = i + 1;
                    EditorUtility.DisplayProgressBar("Loading", "Processing......", m_Context.ProcessPercent);
                    sw.Write(allStr);
                    allStr = "";
                }

                sw.Close();
                fs.Close();
                fs.Dispose();
            }

            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();
            m_Context.Running = false;
            System.Diagnostics.Process.Start(m_Context.AbsSavePath);
        }

        //迭代obj的所有子物体
        private void IterationAllGameObject(Transform obj, string path, ref string allStr, bool writeLayer = false)
        {
            for (var i = 0; i < obj.childCount; i++)
            {
                var child = obj.GetChild(i).gameObject;
                var realPath = path;
                if (!writeLayer)
                {
                    if (child.layer == m_Context.SearchLayer)
                    {
                        realPath += $"->{child.name}\r\n";
                        allStr += realPath;
                    }
                }
                else
                {
                    realPath += $"->{child.name}    ::Layer -> {child.layer}\r\n";
                    allStr += realPath;
                }

                var namePath = $"{path} ->{child.name}";
                IterationAllGameObject(obj.GetChild(i), namePath, ref allStr, writeLayer);
            }
        }

        private void ReplaceAllGameObjectLayer(bool checkLayer = true)
        {
            var allPath = Directory.GetFiles(m_Context.CheckPath, "*.prefab", SearchOption.AllDirectories);
            if (allPath.Length == 0)
            {
                EditorUtility.DisplayDialog("Replace Layer", $"No Prefab in Path: '{m_Context.CheckPath}'", "Ok");
                return;
            }

            m_Context.Running = true;
            m_Context.ProcessIndex = 0;
            m_Context.ProcessLen = allPath.Length;
            for (var i = 0; i < allPath.Length; i++)
            {
                if (File.Exists(allPath[i]))
                {
                    var obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
                    if (obj == null) continue;
                    if (obj.layer == m_Context.SearchLayer)
                    {
                        obj.layer = m_Context.Replacelayer;
                    }
                    else if (!checkLayer)
                    {
                        obj.layer = m_Context.Replacelayer;
                    }

                    IterationReplace(obj.transform, checkLayer);
                }

                m_Context.ProcessIndex = i + 1;
                EditorUtility.DisplayProgressBar("Loading", "Processing......", m_Context.ProcessPercent);
            }

            EditorUtility.ClearProgressBar();
            AssetDatabase.SaveAssets();
            m_Context.Running = false;
        }

        private void IterationReplace(Transform obj, bool checkLayer = true)
        {
            if (obj.childCount == 0) return;
            for (var i = 0; i < obj.childCount; i++)
            {
                var child = obj.GetChild(i).gameObject;
                if (child.layer == m_Context.SearchLayer)
                {
                    child.layer = m_Context.Replacelayer;
                }
                else if (!checkLayer)
                    child.layer = m_Context.Replacelayer;

                IterationReplace(obj.GetChild(i), checkLayer);
            }
        }
    }
}