#nullable enable

using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Filter;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using System;
using System.Diagnostics;
using System.IO;
using UnityEngine;

namespace UVC.Log
{
    public static class ULog
    {
        private static readonly ILog logger = LogManager.GetLogger(typeof(ULog));

        private static readonly bool useUnityDebug = true; // Unity Debug 사용 여부

        static ULog()
        {
            if (!useUnityDebug)
            {
                // unity runtime 일때 
                if (Application.platform == RuntimePlatform.WindowsPlayer)
                {
                    log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(Path.Combine(Application.dataPath, @"Resources\log4net.runtime.xml")));
                }
                // unity editor 일때
                else
                {
                    log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(Path.Combine(Application.dataPath, @"Resources\log4net.editor.xml")));
                    //FileConfigure();
                }
            }
        }


        public static void Debug(string msg)
        {
            if (logger.IsDebugEnabled)
            {
                if (useUnityDebug)
                {
                    UnityEngine.Debug.Log(msg);
                }
                else
                {
                    StackFrame frame = (new StackTrace(true)).GetFrame(1);
                    var method = frame.GetMethod();
                    var type = method.DeclaringType;
                    var name = method.Name;
                    int lineNumber = frame.GetFileLineNumber();

                    logger.Debug(type.Name + "." + name + " [line " + lineNumber + "] " + msg);
                }
            }
        }

        public static void Info(string msg)
        {
            if (logger.IsInfoEnabled)
            {
                if (useUnityDebug)
                {
                    UnityEngine.Debug.Log(msg);
                }
                else
                {
                    StackFrame frame = (new StackTrace(true)).GetFrame(1);
                    var method = frame.GetMethod();
                    var type = method.DeclaringType;
                    var name = method.Name;

                    int lineNumber = frame.GetFileLineNumber();
                    logger.Info(type.Name + "." + name + " [line " + lineNumber + "] " + msg);
                }
            }
        }


        public static void Warning(string msg, Exception? ex = null)
        {
            if (logger.IsWarnEnabled)
            {
                if (useUnityDebug)
                {
                    UnityEngine.Debug.LogWarning(msg + (ex != null ? ", " + ex: ""));
                }
                else
                {
                    StackFrame frame = (new StackTrace(true)).GetFrame(1);
                    var method = frame.GetMethod();
                    var type = method.DeclaringType;
                    var name = method.Name;
                    int lineNumber = frame.GetFileLineNumber();

                    logger.Warn(type.Name + "." + name + " [line " + lineNumber + "] " + msg, ex);
                }
            }
        }

        public static void Error(string msg, Exception? ex = null)
        {
            if (logger.IsErrorEnabled)
            {
                if (useUnityDebug)
                {
                    UnityEngine.Debug.LogError(msg + (ex != null ? ", " + ex : ""));
                }
                else
                {
                    StackFrame frame = (new StackTrace(true)).GetFrame(1);
                    var method = frame.GetMethod();
                    var type = method.DeclaringType;
                    var name = method.Name;
                    int lineNumber = frame.GetFileLineNumber();

                    logger.Error(type.Name + "." + name + " [line " + lineNumber + "] " + msg, ex);
                }
            }
        }

        public static void Fatal(string msg, Exception? ex = null)
        {
            if (logger.IsFatalEnabled)
            {
                if (useUnityDebug)
                {
                    UnityEngine.Debug.LogError(msg + (ex != null ? ", " + ex : ""));
                }
                else
                {
                    StackFrame frame = (new StackTrace(true)).GetFrame(1);
                    var method = frame.GetMethod();
                    var type = method.DeclaringType;
                    var name = method.Name;
                    int lineNumber = frame.GetFileLineNumber();

                    logger.Fatal(type.Name + "." + name + " [line " + lineNumber + "] " + msg, ex);
                }
            }
        }


        /// <summary>
        /// log4net 파일 설정을 구성합니다.
        /// Assets/Resources/log4net.editor.xml log4net.runtime.xml 파일로 구성하였기에 사용안함.
        /// </summary>
        private static void FileConfigure()
        {
            try
            {
                var hierarchy = (Hierarchy)LogManager.GetRepository();

                var patternLayout = new PatternLayout();
                patternLayout.ConversionPattern = "[%date][%thread][%level][%logger] %message%newline";
                patternLayout.ActivateOptions();

                //var folder = new DirectoryInfo(Path.Combine(Application.streamingAssetsPath, "unityLogs"));
                //if (!folder.Exists) folder.Create();

                var fileAppender = new RollingFileAppender
                {
                    File = Path.Combine(System.IO.Directory.GetCurrentDirectory(), @"Logs\"),
                    DatePattern = "yyyy-MM-dd'.log'",
                    AppendToFile = true,
                    RollingStyle = RollingFileAppender.RollingMode.Date,
                    StaticLogFileName = false,
                    Layout = patternLayout,
                };
                fileAppender.AddFilter(new LevelRangeFilter() { LevelMin = Level.Info, LevelMax = Level.Fatal });
                fileAppender.ActivateOptions();

                var fatalFileAppender = new RollingFileAppender
                {
                    File = Path.Combine(System.IO.Directory.GetCurrentDirectory(), @"Logs\fatal.log"),
                    MaxSizeRollBackups = 100,
                    MaximumFileSize = "10MB",
                    AppendToFile = true,
                    RollingStyle = RollingFileAppender.RollingMode.Size,
                    StaticLogFileName = true,
                    Layout = patternLayout,
                };
                fatalFileAppender.AddFilter(new LevelRangeFilter() { LevelMin = Level.Fatal, LevelMax = Level.Fatal });
                fatalFileAppender.ActivateOptions();

                hierarchy.Root.AddAppender(fileAppender);
                hierarchy.Root.AddAppender(fatalFileAppender);

                //var appender = new UnityDefaultLogAppender();
                //appender.Layout = patternLayout;
                //hierarchy.Root.AddAppender(appender);

                hierarchy.Root.Level = Level.All;
                hierarchy.Configured = true;
            }
            catch (Exception ex) { }


        }
    }
}
