using AyCode.Core.Tests.TestModels;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;

namespace AyCode.Core.Benchmarks.Workloads.Scenarios;

/// <summary>
/// System.Text.Json benchmark, String I/O mode. Reference comparison — uses reflection-based metadata
/// (no source-generator opt-in here). Typically NOT in the active suite (commented out in the
/// caller-side <c>CreateSerializers</c>); ranks far behind binary serializers on µs/op but provides
/// a familiar JSON baseline when needed.
/// </summary>
public sealed class SystemTextJsonBenchmark<T> : ISerializerBenchmark where T : class
{
    private readonly T _order;
    private readonly JsonSerializerOptions _options;
    private readonly string _serialized;
    private readonly byte[] _serializedUtf8;

    public BenchmarkEngine Engine => BenchmarkEngine.SystemTextJson;
    public BenchmarkIoMode IoMode => BenchmarkIoMode.String;
    public BenchmarkDispatchMode DispatchMode => BenchmarkDispatchMode.Runtime; // System.Text.Json default uses reflection-based metadata (no source generator opt-in here)
    public Type OrderType => typeof(T);
    public string OptionsPreset { get; }
    public int SerializedSize => _serializedUtf8.Length;
    public long SetupSerializeAllocBytes => 0;
    public long SetupDeserializeAllocBytes => 0;

    public SystemTextJsonBenchmark(T order, string optionsPreset)
    {
        _order = order;
        OptionsPreset = optionsPreset;
        _options = new JsonSerializerOptions
        {
            WriteIndented = false,
            DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
            ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles
        };
        _serialized = JsonSerializer.Serialize(order, _options);
        // Encoding.UTF8.GetBytes(string) does NOT prepend the BOM (the preamble is only emitted by
        // GetPreamble() / stream-level writes), so this produces identical bytes to the prior
        // `new UTF8Encoding(false).GetBytes(_serialized)` call. Size-reporting only.
        _serializedUtf8 = Encoding.UTF8.GetBytes(_serialized);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public void Serialize() => JsonSerializer.Serialize(_order, _options);

    [MethodImpl(MethodImplOptions.NoInlining)]
    public void Deserialize() => JsonSerializer.Deserialize<T>(_serialized, _options);

    public bool VerifyRoundTrip()
    {
        var json = JsonSerializer.Serialize(_order, _options);
        var roundTripped = JsonSerializer.Deserialize<T>(json, _options);
        return RoundTripValidator.DeepEqualsViaJson(_order, roundTripped);
    }
}
