using AyCode.Core.Enums;
using AyCode.Core.Helpers;
using AyCode.Core.Loggers;
using AyCode.Interfaces.Entities;
using AyCode.Utils.Extensions;
using System.Collections.Concurrent;
using AyCode.Core.Consts;

namespace AyCode.Entities;

public abstract class AcLogItemWriterBase<TLogItem> : AcLogWriterBase where TLogItem : class, IAcLogItemClient
{
    protected readonly Mutex MutexLock = new();//new(false, "GLOBAL");

    protected AcLogItemWriterBase() : this(null)
    { }

    protected AcLogItemWriterBase(string? categoryName = null) : base(categoryName)
    { }

    protected AcLogItemWriterBase(AppType appType, LogLevel logLevel, string? categoryName = null) : base(appType, logLevel, categoryName)
    {
    }

    protected virtual TLogItem CreateLogItem(DateTime utcNow, AppType appType, int threadId, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName = null, string? errorType = null, string? exMessage = null)
    {
        var logItem = Activator.CreateInstance<TLogItem>();

        logItem.TimeStampUtc = utcNow;
        logItem.AppType = appType;
        logItem.LogLevel = logLevel;
        logItem.CategoryName = categoryName ?? CategoryName;
        logItem.CallerName = callerMemberName;
        logItem.Text = logText;
        logItem.ThreadId = threadId;

        logItem.ErrorType = errorType;
        logItem.Exception = exMessage;

        return logItem;
    }

    public override void Write(IAcLogItemClient logItem)
        => WriteLogItemAsync(logItem as TLogItem);

    public override void Write(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage)
        => WriteAsync(appType, logLevel, logText, callerMemberName, categoryName, errorType, exMessage);

    protected virtual void WriteAsync(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage)
    {
        if (logLevel < LogLevel) return;

        var utcNow = DateTime.UtcNow;
        var threadId = Environment.CurrentManagedThreadId;

        TaskHelper.RunOnThreadPool(() => WriteLogItem(CreateLogItem(utcNow, appType, threadId, logLevel, logText, callerMemberName, categoryName, errorType, exMessage)));
    }

    public void WriteLogItemAsync(TLogItem? logItem)
    {
        if (logItem == null || logItem.LogLevel < LogLevel) return;

        TaskHelper.RunOnThreadPool(() => WriteLogItem(logItem));
    }

    public void WriteLogItem(TLogItem logItem)
    {
        try
        {
            if (logItem.LogLevel < LogLevel) return;

            using (MutexLock.UseWaitOne())
            {
                WriteLogItemCallback(logItem);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($@"ERROR!!! {nameof(AcLogItemWriterBase<TLogItem>)}->WriteLogItem; ex: {ex.Message}{AcEnv.NL}{AcEnv.NL}{ex}");
            //Console.WriteLine("ERRORORROROR! " + AcEnv.NL + ex);
            //throw;
        }
    }

    protected virtual void WriteLogItemCallback(TLogItem logItem)
    {
        throw new NotImplementedException();
    }

    //private volatile bool _isLocked = false;
    //private readonly object _forLock = new();
    //private readonly List<TLogItem> _logItemsCahce = new();
    //private readonly List<TLogItem> _logItemsCahce2 = new();

    //protected virtual void WriteLogItem(TLogItem logItem, Action<IEnumerable<TLogItem>>? callback = null)
    //{
    //    lock (_forLock) _logItemsCahce.Add(logItem);

    //    if (_isLocked) return;
        

    //    using (MutexLock.UseWaitOne())
    //    {
    //        _isLocked = true;

    //        _logItemsCahce2.Clear();
            
    //        lock (_forLock)
    //        {
    //            _logItemsCahce2.AddRange(_logItemsCahce);
                
    //            _logItemsCahce.Clear();
    //        }

    //        callback?.Invoke(_logItemsCahce2);
    //    }

    //    _isLocked = false;
    //}
}