using System;
using System.IO;
using System.Threading;

namespace XGame.Framework.Logger
{
    internal class LogWriter : ILogWriter, IDisposable
    {
        private LogType _logType;
        private MMFile _mmfile;
        private ILogCompressor _compressor;

        public object _syncRoot;
        private object SyncRoot
        {
            get
            {
                if (this._syncRoot == null)
                {
                    //如果_syncRoot和null相等，将new object赋值给 _syncRoot
                    //Interlocked.CompareExchange方法保证多个线程在使用 syncRoot时是线程安全的
                    Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
                }
                return this._syncRoot;
            }
        }
        public LogWriter(LogType logType, MMFile mmfile, ILogCompressor compressor)
        {
            _logType = logType;
            _mmfile = mmfile;
            _compressor = compressor;
        }
        #region 接口实现
        public void Write(string contents)
        {
            lock (this.SyncRoot)
            {
                contents += '\n';
                var buffer = System.Text.Encoding.UTF8.GetBytes(contents);
                WriteToCache(buffer, 0, buffer.Length);
            }
        }
        public void Flush()
        {
            lock (this.SyncRoot)
            {
                WriteToFile();
                _mmfile.Reset();
            }
        }

        public void Dispose()
        {
            _mmfile.Dispose();
            _mmfile = null;
        }
        #endregion
        private void WriteToFile()
        {
            try
            {
                var header = _mmfile.ReadHeader();
                if (header.position <= 0) return;
                var buffer = _mmfile.ReadAll();
                if (_compressor != null)
                {
                    buffer = _compressor.Compress(buffer);
                }
                // 每次写入的时候都进行判断文件夹是否存在
                var dirPath = GetLogDirectory();
                var logFilePath = $"{dirPath}/{DateTime.UtcNow}{LogDefine.FileExtension}";
                File.WriteAllBytes(logFilePath, buffer);
            }
            catch (Exception ex)
            {
                UnityEngine.Debug.LogException(ex);
            }
            
        }

        private void WriteToCache(byte[] buffer, int offset, int length)
        {
            try
            {
                if (!_mmfile.Write(buffer, offset, length))
                {
                    WriteToFile();
                    _mmfile.Reset();
                    WriteToCache(buffer, offset, length);
                }
            }
            catch (Exception ex)
            {
                UnityEngine.Debug.LogException(ex);
            }
        }

        private string GetLogDirectory()
        {
            var dirPath = _logType == LogType.Code ? LogDefine.CodeLogPath : LogDefine.EventLogPath;
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }
            return dirPath;
        }

    }
}
