using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static XKRS.Common.Model.Helper.EnumHelper;

namespace XKRS.Common.Model.Helper
{
    public class LoggerHelper
    {
        public event Action<DateTime, string> OnLogExceptionRaised;

        public string LogPath { get; set; }//获取日志地址
        public string LogPrefix { get; set; }
        LogLevel LogLevel = LogLevel.Information;
        public LoggerHelper() { }
        public LoggerHelper(string logPath, string logPrefix, LogLevel logLevel = LogLevel.Information)
        {
            LogPath = logPath;
            LogPrefix = logPrefix;
            LogLevel = logLevel;
        }
        public void SetLogLevel(LogLevel logLevel)
        {
            if (LogLevel != logLevel)
                LogLevel = logLevel;
        }
        //耗时操作从 _taskFactory分配线程
        //public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
        readonly ConcurrentQueue<LogMsg> _logQueue = new ConcurrentQueue<LogMsg>();
        Task _logTask = null;
        readonly object _logLock = new object();
        public async void LogAsync(LogMsg msg)
        {
            await Task.Run(() =>
            {
                if (string.IsNullOrEmpty(LogPath) || string.IsNullOrWhiteSpace(LogPath))
                {
                    return;
                }
                //Enqueue:将对象添加到ConcurrentQueue的结尾处
                _logQueue.Enqueue(msg);
                lock (_logLock)
                {
                    if (_logTask == null)
                    {
                        _logTask = Task.Run(async () =>
                        {
                            string filePath = Path.Combine(LogPath, $"{(string.IsNullOrWhiteSpace(LogPrefix) ? "Log_" : ("Log_" + LogPrefix + "_"))}{DateTime.Now.ToString("yyyyMMdd")}.txt");
                            try
                            {
                                if (!StaticHelper.CheckFileCanUse(filePath))
                                {
                                    OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}被占用，无法写入");
                                    return;
                                }
                                using (StreamWriter writer=new StreamWriter(filePath, true, Encoding.UTF8))
                                {
                                    while (true)
                                    {
                                        if (!Directory.Exists(LogPath))
                                        {
                                            Directory.CreateDirectory(LogPath);
                                        }
                                        while (_logQueue.Count > 0)
                                        {
                                            //尝试移出并返回并发队列开头处的对象
                                            if(_logQueue.TryDequeue(out LogMsg log))
                                            {
                                                if (log.LogLevel >= LogLevel)
                                                {
                                                    //将行结束符的字符串写入文本字符串或流
                                                    writer.WriteLine($"{log.LogTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}[{log.ThreadId}]\t{log.LogLevel.GetEnumDescription()}");
                                                }
                                            }
                                        }
                                        writer.Flush();
                                        //delay:创建将在延迟后完成的任务
                                        await Task.Delay(2000);
                                    }
                                }
                            }
                            catch(Exception ex)
                            {
                                OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常：{ex.GetExceptionMessage()}");
                            }
                        });
                    }
                }
            });
        }
        public void LogAsync(DateTime dt,LogLevel logLevel,string msg)
        {
            LogAsync(new LogMsg(dt, logLevel, msg));
        }
    }

    public class LogMsg
    {
        public DateTime LogTime { get; set; }
        public LogLevel LogLevel { get; set; }
        public string Msg { get; set; }
        public string MsgSource { get; set; }

        public int ThreadId { get; set; }
        public LogMsg() { }

        public LogMsg(DateTime dt,LogLevel logLevel,string msg)
        {
            LogTime = dt;
            LogLevel = logLevel;
            Msg = msg;
        }
        public override string ToString()
        {
            return $"{LogTime.ToString("HH:mm:ss.fff")}\t{MsgSource}\t{Msg}";

        }
    }
}
