using Amazon.XRay.Recorder.Core;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Options;
using System.Runtime.InteropServices;
namespace SampleWebApp.AppLogger;
/// 
/// Custom Console Logging Formatter to add AWS X-Ray TraceId as suffix for logs 
/// 
public class XrayCustomFormatter : ConsoleFormatter, IDisposable
{
    private bool isDisposed;
    private readonly string _padding = " ";
    private readonly IDisposable _optionsReloadToken;
    private XrayCustomFormatterOptions _formatterOptions;
    public XrayCustomFormatter(IOptionsMonitor options)
        : base(nameof(XrayCustomFormatter)) =>
        (_optionsReloadToken, _formatterOptions) =
            (options.OnChange(ReloadLoggerOptions), options?.CurrentValue);
    private void ReloadLoggerOptions(XrayCustomFormatterOptions options) =>
        _formatterOptions = options;
    public override void Write(
        in LogEntry logEntry,
        IExternalScopeProvider scopeProvider,
        TextWriter textWriter)
    {
        string message =
            logEntry.Formatter(
                logEntry.State, logEntry.Exception);
        if (message == null || textWriter == null)
        {
            return;
        }
        //textWriter.Write(DateTime.UtcNow.ToString(_formatterOptions.TimestampFormat) + " ");
        textWriter.Write(logLevelString(logEntry.LogLevel));
        textWriter.Write(":");
        textWriter.Write(_padding);
        textWriter.Write(message);
        textWriter.Write(_padding);
        WriteTraceIdSuffix(textWriter);
        textWriter.Write(_padding);
        // exception message
        if (logEntry.Exception != null)
        {
            textWriter.Write("Exception: ");
            string newMessage = logEntry.Exception
                                         .ToString()?
                                         .Replace(Environment.NewLine, " ", StringComparison.Ordinal);
            textWriter.Write(newMessage);
        }
        textWriter.Write(Environment.NewLine);
    }
    private void WriteTraceIdSuffix(TextWriter textWriter)
    {
        if (_formatterOptions.EnableTraceIdInjection && AWSXRayRecorder.Instance.IsEntityPresent())
        {
            textWriter.Write($"TraceId: {AWSXRayRecorder.Instance?.GetEntity()?.TraceId}");
        }
    }
    private static string logLevelString(LogLevel logLevel)
    {
        return logLevel switch
        {
            LogLevel.Trace => "trce",
            LogLevel.Debug => "dbug",
            LogLevel.Information => "info",
            LogLevel.Warning => "warn",
            LogLevel.Error => "fail",
            LogLevel.Critical => "crit",
            _ => throw new ArgumentOutOfRangeException(nameof(logLevel))
        };
    }
    // Dispose() calls Dispose(true)
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    // The bulk of the clean-up code is implemented in Dispose(bool)
    protected virtual void Dispose(bool disposing)
    {
        if (isDisposed) return;
        if (disposing)
        {
            _optionsReloadToken?.Dispose();
        }
        isDisposed = true;
    }
}