using System.Globalization;
using Xunit.Abstractions;

namespace NATS.Server.Benchmark.Tests.Harness;

/// <summary>
/// Writes side-by-side benchmark comparison output to xUnit's ITestOutputHelper.
/// </summary>
public static class BenchmarkResultWriter
{
    public static void WriteComparison(ITestOutputHelper output, BenchmarkResult goResult, BenchmarkResult dotnetResult)
    {
        var ratio = dotnetResult.MessagesPerSecond / goResult.MessagesPerSecond;

        output.WriteLine($"=== {goResult.Name} ===");
        output.WriteLine($"Go:      {FormatRate(goResult.MessagesPerSecond)} msg/s  |  {goResult.MegabytesPerSecond:F1} MB/s  |  {goResult.Duration.TotalMilliseconds:F0} ms");
        output.WriteLine($".NET:    {FormatRate(dotnetResult.MessagesPerSecond)} msg/s  |  {dotnetResult.MegabytesPerSecond:F1} MB/s  |  {dotnetResult.Duration.TotalMilliseconds:F0} ms");
        output.WriteLine($"Ratio:   {ratio:F2}x (.NET / Go)");

        if (goResult.Latencies is not null && dotnetResult.Latencies is not null)
        {
            output.WriteLine("");
            output.WriteLine("Latency (us):");
            output.WriteLine($"  {"",8} {"P50",10} {"P95",10} {"P99",10} {"Min",10} {"Max",10}");
            WriteLatencyRow(output, "Go", goResult.Latencies);
            WriteLatencyRow(output, ".NET", dotnetResult.Latencies);
        }

        output.WriteLine("");
    }

    public static void WriteSingle(ITestOutputHelper output, BenchmarkResult result)
    {
        output.WriteLine($"=== {result.Name} ({result.ServerType}) ===");
        output.WriteLine($"{FormatRate(result.MessagesPerSecond)} msg/s  |  {result.MegabytesPerSecond:F1} MB/s  |  {result.Duration.TotalMilliseconds:F0} ms");

        if (result.Latencies is not null)
        {
            output.WriteLine("");
            output.WriteLine("Latency (us):");
            output.WriteLine($"  {"",8} {"P50",10} {"P95",10} {"P99",10} {"Min",10} {"Max",10}");
            WriteLatencyRow(output, result.ServerType, result.Latencies);
        }

        output.WriteLine("");
    }

    private static void WriteLatencyRow(ITestOutputHelper output, string label, LatencyPercentiles p)
    {
        output.WriteLine($"  {label,8} {p.P50Us,10:F1} {p.P95Us,10:F1} {p.P99Us,10:F1} {p.MinUs,10:F1} {p.MaxUs,10:F1}");
    }

    private static string FormatRate(double rate)
        => rate.ToString("N0", CultureInfo.InvariantCulture).PadLeft(15);
}
