using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Check.Main.Common
{
    /// 
    /// 一个线程安全的、基于队列的日志记录器。
    /// 使用一个独立的后台线程来处理文件写入,避免业务线程阻塞。
    /// 
    public static class ThreadSafeLogger
    {
        // 使用线程安全的队列作为日志消息的缓冲区
        private static readonly BlockingCollection _logQueue = new BlockingCollection();
        // 日志写入线程
        private static Thread _logWriterThread;
        private static StreamWriter _logFileWriter;
        // 事件,用于将格式化后的日志消息广播给UI等监听者
        public static event Action OnLogMessage;
        /// 
        /// 初始化日志记录器,启动后台写入线程。
        /// 
        public static void Initialize()
        {
            try
            {
                string logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
                Directory.CreateDirectory(logDirectory);
                string logFileName = $"Log_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt";
                string logFilePath = Path.Combine(logDirectory, logFileName);
                _logFileWriter = new StreamWriter(logFilePath, append: true, encoding: Encoding.UTF8) { AutoFlush = true };
                // 创建并启动后台线程
                _logWriterThread = new Thread(ProcessLogQueue)
                {
                    IsBackground = true, // 设置为后台线程,这样主程序退出时它会自动终止
                    Name = "LogWriterThread"
                };
                _logWriterThread.Start();
                Log("日志系统已初始化。");
            }
            catch (Exception ex)
            {
                // 如果初始化失败,尝试通过事件通知UI
                OnLogMessage?.Invoke($"[CRITICAL] 日志系统初始化失败: {ex.Message}");
            }
        }
        /// 
        /// 将一条日志消息添加到队列中。这个方法是线程安全的,且执行速度非常快。
        /// 
        /// 原始日志消息。
        public static void Log(string message)
        {
            string formattedMessage = $"[{DateTime.Now:HH:mm:ss.fff}] {message}";
            _logQueue.Add(formattedMessage);
        }
        /// 
        /// 后台线程的工作方法。它会持续不断地从队列中取出消息并处理。
        /// 
        private static void ProcessLogQueue()
        {
            // GetConsumingEnumerable会阻塞等待,直到有新的项加入队列或队列被标记为已完成
            foreach (string message in _logQueue.GetConsumingEnumerable())
            {
                try
                {
                    // 1. 写入文件
                    _logFileWriter?.WriteLine(message);
                    // 2. 触发事件,通知UI
                    OnLogMessage?.Invoke(message);
                }
                catch
                {
                    // 忽略在日志线程本身发生的写入错误
                }
            }
        }
        /// 
        /// 关闭日志记录器,释放资源。
        /// 
        public static void Shutdown()
        {
            Log("日志系统正在关闭...");
            // 标记队列不再接受新的项目。这会让ProcessLogQueue中的循环在处理完所有剩余项后自然结束。
            _logQueue.CompleteAdding();
            // 等待日志线程处理完所有剩余的日志,最多等待2秒
            _logWriterThread?.Join(2000);
            // 关闭文件流
            _logFileWriter?.Close();
            _logFileWriter?.Dispose();
        }
    }
}