using AyCode.Core.Consts;
using AyCode.Core.Enums;
using AyCode.Utils.Extensions;

namespace AyCode.Core.Loggers;

public interface IAcTextLogWriterBase : IAcLogWriterBase
{}

public abstract class AcTextLogWriterBase : AcLogWriterBase, IAcTextLogWriterBase
{
    protected AcTextLogWriterBase() : this(null)
    { }

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

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

    public override void Write(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? ex)
    {
        if (logLevel < LogLevel) return;
        
        WriteText(GetDiagnosticText(appType, logLevel, logText, callerMemberName, categoryName, errorType, ex), logLevel);

    }

    public override void Write(IAcLogItemClient logItem)
    {
        if (logItem.LogLevel < LogLevel) return;

        WriteText(GetDiagnosticText(logItem), logItem.LogLevel);
    }

    protected virtual void WriteText(string? logText, LogLevel loglevel)
    {
        throw new NotImplementedException();
    }

    protected string GetDiagnosticText(IAcLogItemClient logItem)
        => GetDiagnosticText(logItem.TimeStampUtc, logItem.AppType, logItem.LogLevel, logItem.ThreadId, logItem.Text, logItem.CallerName, logItem.CategoryName, logItem.ErrorType, logItem.Exception);

    protected string GetDiagnosticText(LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName = null, Exception? ex = null)
        => GetDiagnosticText(AppType, logLevel, logText, callerMemberName, categoryName, ex?.GetType().Name, ex?.ToString());

    protected string GetDiagnosticText(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage)
        => GetDiagnosticText(DateTime.UtcNow, appType, logLevel, Environment.CurrentManagedThreadId, logText, callerMemberName, categoryName, errorType, exMessage);

    protected string GetDiagnosticText(DateTime utcNow, AppType appType, LogLevel logLevel, int threadId, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage)
    {
        if (LogLevel > logLevel) return string.Empty;

        if(categoryName.IsNullOrWhiteSpace()) categoryName = CategoryName;

        return $"[{utcNow.ToLocalTime():HH:mm:ss.fff}] [{appType.ToString()[0]}] {"[" + logLevel + "]",-9} {"[" + categoryName + "->" + callerMemberName + "]",-54}  {"[" + threadId + "]",5} {logText}{ErrorText(errorType, exMessage)}";
    }

    protected string ErrorText(Exception? ex)
    {
        return ex == null ? string.Empty : ErrorText(ex.GetType().Name, ex.ToString());
    }

    protected virtual string ErrorText(string? errorType, string? exMessage)
    {
        if (errorType.IsNullOrWhiteSpace() && exMessage.IsNullOrWhiteSpace()) return string.Empty;

        return string.IsNullOrWhiteSpace(errorType) ? string.Empty : $"{AcEnv.NL}[{errorType.ToUpper()}]: {exMessage}";
    }
}