using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Formatting.Display;

namespace NexusReader.Maui.Infrastructure.Logging;

public static class SerilogConfiguration
{
    private const string OutputTemplate = 
        "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [ThreadId: {ThreadId}] [{SourceContext}] {Message:lj}{NewLine}{Exception}";

    public static MauiAppBuilder RegisterLogging(this MauiAppBuilder builder)
    {
        // 1. Ensure logs directory exists in secure sandbox
        var logDir = Path.Combine(Microsoft.Maui.Storage.FileSystem.AppDataDirectory, "logs");
        if (!Directory.Exists(logDir))
        {
            Directory.CreateDirectory(logDir);
        }
        var logPath = Path.Combine(logDir, "log-.txt");

        // 2. Inject sandboxed log path dynamically into configuration provider
        builder.Configuration["Serilog:WriteTo:0:Args:configure:0:Args:path"] = logPath;

        // 3. Configure Serilog Logger Configuration using App Configuration settings
        var loggerConfig = new LoggerConfiguration()
            .ReadFrom.Configuration(builder.Configuration)
            .Enrich.With(new ThreadIdEnricher());

        // 4. Platform-specific and environment-specific sinks
#if ANDROID
        // Direct Native Android Logcat Sink (JNI bindings for native diagnostics)
        loggerConfig.WriteTo.Sink(
            new AndroidLogcatSink(new MessageTemplateTextFormatter(OutputTemplate, null)),
            restrictedToMinimumLevel: LogEventLevel.Debug);
#endif

        // 5. Initialize the static Serilog Log
        Log.Logger = loggerConfig.CreateLogger();

        // 6. Connect Serilog to Microsoft.Extensions.Logging
        builder.Logging.ClearProviders();
        builder.Logging.AddSerilog(dispose: true);

        return builder;
    }
}

/// <summary>
/// A custom self-contained thread enricher to avoid unnecessary NuGet packages.
/// </summary>
internal sealed class ThreadIdEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadId", Environment.CurrentManagedThreadId));
    }
}

#if ANDROID
/// <summary>
/// A high-performance, direct Android Logcat Sink utilizing native Android APIs.
/// </summary>
internal sealed class AndroidLogcatSink : ILogEventSink
{
    private readonly ITextFormatter _formatter;
    private const string Tag = "NexusReader";

    public AndroidLogcatSink(ITextFormatter formatter)
    {
        _formatter = formatter ?? throw new ArgumentNullException(nameof(formatter));
    }

    public void Emit(LogEvent logEvent)
    {
        using var writer = new StringWriter();
        _formatter.Format(logEvent, writer);
        var message = writer.ToString().Trim();

        switch (logEvent.Level)
        {
            case LogEventLevel.Verbose:
                Android.Util.Log.Verbose(Tag, message);
                break;
            case LogEventLevel.Debug:
                Android.Util.Log.Debug(Tag, message);
                break;
            case LogEventLevel.Information:
                Android.Util.Log.Info(Tag, message);
                break;
            case LogEventLevel.Warning:
                Android.Util.Log.Warn(Tag, message);
                break;
            case LogEventLevel.Error:
                Android.Util.Log.Error(Tag, message);
                break;
            case LogEventLevel.Fatal:
                Android.Util.Log.Wtf(Tag, message);
                break;
        }
    }
}
#endif
