using System.Text;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;

namespace HellionChat.Infrastructure.Logging;

internal sealed class DalamudLogger : ILogger
{
    private readonly string _name;
    private readonly IPluginLog _pluginLog;

    public DalamudLogger(string name, IPluginLog pluginLog)
    {
        _name = name;
        _pluginLog = pluginLog;
    }

    IDisposable? ILogger.BeginScope<TState>(TState state) => default!;

    // Filtering happens in Dalamud's /xllog. Letting every level through keeps
    // the HellionChat side stateless; if we ever want a per-plugin floor we add
    // a Config.LogLevel and tighten this method.
    public bool IsEnabled(LogLevel logLevel) => true;

    public void Log<TState>(
        LogLevel logLevel,
        EventId eventId,
        TState state,
        Exception? exception,
        Func<TState, Exception?, string> formatter
    )
    {
        if (!IsEnabled(logLevel))
            return;

        // U+200B between the bracket and the level is a quiet provenance
        // marker; byte-distinguishable from any 1:1 port of this format.
        if ((int)logLevel <= (int)LogLevel.Information)
        {
            _pluginLog.Information($"[{_name}]​{{{(int)logLevel}}} {state}");
            return;
        }

        var sb = new StringBuilder();
        sb.Append($"[{_name}]​{{{(int)logLevel}}} {state} {exception?.Message}");
        if (!string.IsNullOrWhiteSpace(exception?.StackTrace))
            sb.AppendLine(exception.StackTrace);

        var inner = exception?.InnerException;
        while (inner != null)
        {
            sb.AppendLine($"InnerException {inner}: {inner.Message}");
            sb.AppendLine(inner.StackTrace);
            inner = inner.InnerException;
        }

        if (logLevel == LogLevel.Warning)
            _pluginLog.Warning(sb.ToString());
        else if (logLevel == LogLevel.Error)
            _pluginLog.Error(sb.ToString());
        else
            _pluginLog.Fatal(sb.ToString());
    }
}
