using System.Diagnostics;
using System.Runtime.CompilerServices;
using AyCode.Core.Consts;
using AyCode.Core.Enums;

namespace AyCode.Core.Loggers;

public abstract class AcLogWriterBase : IAcLogWriterBase
{
    public string? CategoryName { get; }

    protected AppType AppType { get; set; } = AppType.Server;
    protected LogLevel LogLevel { get; set; } = LogLevel.Error;

    protected AcLogWriterBase() : this(null)
    {}

    protected AcLogWriterBase(string? categoryName = null)
    {
        CategoryName = categoryName ?? "...";

        try
        {
            AppType = AcEnv.AppConfiguration.GetEnum<AppType>("AyCode:Logger:AppType");

            //AppType = (AppType)Enum.Parse(typeof(AppType), AcEnv.AppConfiguration["AyCode:Logger:AppType"], true);

            var writerSettings = AcEnv.AppConfiguration.GetSection("AyCode:Logger:LogWriters")
                .GetChildren()
                .FirstOrDefault(logWriter => logWriter["LogWriterType"]?.ToLower().Equals(GetType().AssemblyQualifiedName, StringComparison.CurrentCultureIgnoreCase) ?? false);

            if (writerSettings != null) LogLevel = writerSettings.GetEnum<LogLevel>("LogLevel");
            else Console.Error.WriteLine($"Not found appSettings.json LogWriterType! {GetType().Name}");
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"{GetType().Name}; {ex}");
        }
    }

    protected AcLogWriterBase(AppType appType, LogLevel logLevel, string? categoryName = null)
    {
        AppType = appType;
        LogLevel = logLevel;

        CategoryName = categoryName ?? "...";
    }

    public void Detail(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Write(AppType, LogLevel.Detail, text, memberName, categoryName ?? CategoryName);
    
    [Conditional("DEBUG")]
    public void DetailConditional(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Detail(text, categoryName, memberName);

    public void Debug(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Write(AppType, LogLevel.Debug, text, memberName, categoryName ?? CategoryName);

    [Conditional("DEBUG")]
    public void DebugConditional(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Debug(text, categoryName, memberName);

    public void Info(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Write(AppType, LogLevel.Info, text, memberName, categoryName ?? CategoryName);

    [Conditional("DEBUG")]
    public void InfoConditional(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Info(text, categoryName, memberName);

    public void Warning(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Write(AppType, LogLevel.Warning, text, memberName, categoryName ?? CategoryName);

    [Conditional("DEBUG")]
    public void WarningConditional(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Warning(text, categoryName, memberName);

    public void Suggest(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Write(AppType, LogLevel.Suggest, text, memberName, categoryName ?? CategoryName);

    [Conditional("DEBUG")]
    public void SuggestConditional(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Suggest(text, categoryName, memberName);

    public void Error(string? text, Exception? ex = null, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Write(AppType, LogLevel.Error, text, memberName, categoryName ?? CategoryName, ex);

    [Conditional("DEBUG")]
    public void ErrorConditional(string? text, Exception? ex = null, string? categoryName = null, [CallerMemberName] string? memberName = null)
        => Error(text, ex, categoryName, memberName);

    public void Write(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName)
        => Write(appType, logLevel, logText, callerMemberName, categoryName, null, null);

    [Conditional("DEBUG")]
    public void WriteConditional(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName)
        => Write(appType, logLevel, logText, callerMemberName, categoryName, null, null);

    public void Write(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, Exception? ex)
        => Write(appType, logLevel, logText, callerMemberName, categoryName, ex?.GetType().Name, ex?.ToString());

    [Conditional("DEBUG")]
    public void WriteConditional(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, Exception? ex)
        => Write(appType, logLevel, logText, callerMemberName, categoryName, ex);

    public virtual void Write(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage)
    {
        throw new NotImplementedException();
    }

    [Conditional("DEBUG")]
    public void WriteConditional(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage)
        => Write(appType, logLevel, logText, callerMemberName, categoryName, errorType, exMessage);


    public virtual void Write(IAcLogItemClient logItem)
    {
        throw new NotImplementedException();
    }

    [Conditional("DEBUG")]
    public void WriteConditional(IAcLogItemClient logItem) => Write(logItem);
}