using XGame.Editor.Build;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;

namespace XGame.Editor.Compiler
{
    //[InitializeOnLoad]
    public static class CompileScriptsHandle
    {
        private static CompileResult result;

        [UnityEditor.Callbacks.DidReloadScripts]
        static void OnDidReloadScripts()
        {
            //Debug.Log("CompileScriptsHandle OnDidReloadScripts.");
            EditorApplication.quitting -= OnQuit;
            EditorApplication.quitting += OnQuit;
            CompilationPipeline.compilationFinished -= OnCompilationFinished;
            CompilationPipeline.compilationFinished += OnCompilationFinished;
            CompilationPipeline.assemblyCompilationFinished -= OnAssemblyCompilationFinished;
            CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished;
            //加载 初始化ICompileEvents
            if (HasEvents)
            {
                EditorApplication.update += OnUpdate;
            }
            //Debug.Log($"CompileScriptsHandle InitializeOnLoad. isCompiling: {EditorApplication.isCompiling}");
        }
        //[InitializeOnLoadMethod]
        //static void OnInitializeOnLoadMethod()
        //{
        //    Debug.Log("CompileScriptsHandle OnInitializeOnLoadMethod.");
        //}
        /// <summary>
        /// 监听编辑器退出事件
        /// </summary>
        private static void OnQuit()
        {
            //Debug.Log("EditorApplication OnQuit.");
            Clear();
        }
        /// <summary>
        /// 监听Assembly编译事件
        /// 编译失败时需要记录失败状态
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="messages"></param>
        private static void OnAssemblyCompilationFinished(string obj, CompilerMessage[] messages)
        {
            //Debug.Log($"OnAssemblyCompilationFinished. obj:{obj?.ToString() ?? "null"} msgCount:{messages?.Length ?? 0}");
            if (messages != null && HasEvents)
            {
                foreach(var msg in messages)
                {
                    if (msg.type == CompilerMessageType.Error)
                    {
                        result.isFailed = true;
                        result.message = msg.message;
                        if (result.isCopyAssemblyFailed == false && msg.message.Contains("Copying assembly from"))
                        {
                            //assembly拷贝失败
                            result.isCopyAssemblyFailed = true;
                        }
                        //打印错误信息
                        BuildLog.Error($"OnAssemblyCompilation error. msg:{msg.message} file:{msg.file} line:{msg.line} col:{msg.column}");
                    }
                }
            }
        }
        /// <summary>
        /// 监听编译结束回调事件
        /// 编译失败时 Unity 不会执行InitializeOnLoad
        /// 需要主动执行回调事件
        /// </summary>
        /// <param name="obj"></param>
        private static void OnCompilationFinished(object obj)
        {
            //Debug.Log($"OnCompilationFinished. obj:{obj?.ToString() ?? "null"}");
            if (result.isFailed == false) return;
            //编译失败，主动执行回调
            if (HasEvents)
            {
                EditorApplication.update += OnUpdate;
            }
        }

        private static void OnUpdate()
        {
            //Debug.Log($"CompileScriptsHandle OnUpdate. isCompiling: {EditorApplication.isCompiling}  isFailed:{result.isFailed}");
            EditorApplication.update -= OnUpdate;
            if (UnityEditorInternal.InternalEditorUtility.inBatchMode == false && result.isFailed && result.isCopyAssemblyFailed)
            {
                //非BatchMode下， 编译失败，并且是拷贝Assembly失败，重新编译
                BuildLog.Log($"Compile Scripts Error: Assembly copy failed. Restart RequestScriptCompilation.");
                result = default;
                CompilationPipeline.RequestScriptCompilation();
                return;
            }
            var events = ReadEvents();
            if (events != null)
            {
                var tempResult = result;
                result = default;
                for (int i = 0; i < events.Length; i++)
                {
                    if (tempResult.isFailed)
                    {
                        events[i].OnCompileFailed(tempResult);
                    }
                    else
                    {
                        events[i].OnCompileSuccess();
                    }
                }
                events = null;
            }
        }
        private static string OutputPath
        {
            get
            {
                return Path.GetFullPath($"{Application.dataPath}/../ExtAssets/Editor/CompileEvents.json").Replace("\\", "/");
            }
        }
        /// <summary>
        /// 是否有监听事件
        /// </summary>
        private static bool HasEvents => File.Exists(OutputPath);
        public static void RegistEvent(ICompileEvent compileEvent)
        {
            var filePath = OutputPath;
            var dir = Path.GetDirectoryName(filePath);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var str = $"<type:{compileEvent.GetType().AssemblyQualifiedName} value:{LitJson.JsonMapper.ToJson(compileEvent)}/>";
            try
            {
                var writer = File.Exists(filePath) ? new StreamWriter(filePath, true) : new StreamWriter(filePath);
                writer.WriteLine(str);
                writer.Flush();
                writer.Close();
                BuildLog.Log($"CompileScriptsHandle RegistEvent:{str}");
            }
            catch (Exception ex)
            {
                BuildLog.Exception(ex);
            }


        }
        private static ICompileEvent[] ReadEvents()
        {
            var path = OutputPath;

            if (File.Exists(path))
            {
                List<ICompileEvent> lst = new List<ICompileEvent>();
                try
                {
                    Regex regex = new Regex(@"<type:(.+?) value:(.+?)/>", RegexOptions.Multiline);
                    var lines = File.ReadAllLines(path);
                    foreach (var line in lines)
                    {
                        var match = regex.Match(line);
                        if (match.Success)
                        {
                            var typeName = match.Groups[1].Value;
                            var eventValue = match.Groups[2].Value;
                            BuildLog.Log($"CompileScriptsHandle ReadEvents type:{typeName} value:{eventValue}");
                            Type type = Type.GetType(typeName);
                            var compileEvent = LitJson.JsonMapper.ToObject(eventValue, type) as ICompileEvent;
                            lst.Add(compileEvent);
                        }
                    }
                    lst.Sort((a, b) =>
                    {
                        return a.Priority - b.Priority;
                    });
                }
                catch (Exception ex)
                {
                    BuildLog.Exception(ex);
                }
                //删除文件
                Clear();
                return lst.ToArray();
            }
            return null;
        }

         
        public static void Clear()
        {
            var path = OutputPath;
            if (File.Exists(path))
            {
                File.Delete(path);
            }
        }
    }
}
