using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Tests.TestModels;
using System.Buffers;
using System.Runtime.CompilerServices;

namespace AyCode.Core.Benchmarks.Workloads.Scenarios;

/// <summary>
/// Benchmarks AcBinary via the IBufferWriter overload, allocating a FRESH ArrayBufferWriter on EVERY call.
/// One-shot scenario — represents code that doesn't reuse a writer across calls.
/// Uses BufferWriterChunkSize=4096 (production-realistic, SignalR-aligned) instead of the 65535 default —
/// otherwise AcBinary would request 64KB upfront via GetSpan(), forcing the fresh ABW to allocate 64KB
/// regardless of payload size (heavy over-allocation for small payloads).
/// </summary>
public sealed class AcBinaryFreshBufferWriterBenchmark<T> : ISerializerBenchmark where T : class
{
    private readonly T _order;
    private readonly AcBinarySerializerOptions _options;
    private readonly byte[] _serialized;

    public BenchmarkEngine Engine => BenchmarkEngine.AcBinary;
    public BenchmarkIoMode IoMode => BenchmarkIoMode.BufWrNew;
    public BenchmarkDispatchMode DispatchMode => _options.UseGeneratedCode ? BenchmarkDispatchMode.SGen : BenchmarkDispatchMode.Runtime;
    public Type OrderType => typeof(T);
    public string OptionsPreset { get; }
    public int SerializedSize => _serialized.Length;
    public long SetupSerializeAllocBytes => 0;
    public long SetupDeserializeAllocBytes => 0;
    public string OptionsDescription => BenchmarkOptions.BuildAcBinary(_options, $", BufferSize={_options.BufferWriterChunkSize}B");

    public AcBinaryFreshBufferWriterBenchmark(T order, AcBinarySerializerOptions options, string optionsPreset)
    {
        _order = order;
        // BufferWriterChunkSize comes from the caller (central source of truth in CreateSerializers
        // — the binaryFastMode4KbChunk options instance). Do NOT mutate _options here; tune the chunk
        // size in CreateSerializers only.
        _options = options;
        OptionsPreset = optionsPreset;
        _serialized = AcBinarySerializer.Serialize(order, _options);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public void Serialize()
    {
        var abw = new ArrayBufferWriter<byte>();  // FRESH every call — alloc + grow as needed
        AcBinarySerializer.Serialize(_order, abw, _options);
    }

    // BufWr semantic: read from a ReadOnlySequence<byte> (the ROS overload), NOT from byte[] —
    // single-segment array-backed sequence triggers the fast-path in AcBinaryDeserializer.cs:298 which
    // redirects to the byte[] overload. This means the bench actually exercises the ROS-input path
    // (the production-realistic surface for SignalR / Pipe consumers) rather than secretly testing
    // byte[] Deser under the BufWr label.
    [MethodImpl(MethodImplOptions.NoInlining)]
    public void Deserialize() => AcBinaryDeserializer.Deserialize<T>(new ReadOnlySequence<byte>(_serialized), _options);

    public bool VerifyRoundTrip()
    {
        var abw = new ArrayBufferWriter<byte>();
        AcBinarySerializer.Serialize(_order, abw, _options);
        var roundTripped = AcBinaryDeserializer.Deserialize<T>(new ReadOnlySequence<byte>(abw.WrittenMemory), _options);
        return RoundTripValidator.DeepEqualsViaJson(_order, roundTripped);
    }
}
