using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Tests.TestModels;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Jobs;

namespace AyCode.Core.Benchmarks;

/// <summary>
/// JIT disassembly benchmark for AcBinarySerializer hot path analysis.
/// Shows actual x64 assembly generated by the JIT to verify inlining decisions.
/// 
/// Usage: dotnet run -c Release -- --filter *JitDisassemblyBenchmark*
/// Or from Program.cs: --jitasm
/// 
/// Output: BenchmarkDotNet artifacts folder contains .asm files with full disassembly.
/// Look for:
/// - WritePropertyOrSkip / WritePropertyMarkerless: are they inlined or called?
/// - WriteInt32 / WriteFloat64Unsafe / etc.: inlined into the caller or separate calls?
/// - context parameter passing: register usage (RCX/RDX/R8/R9)
/// </summary>
[SimpleJob(RuntimeMoniker.Net90)]
[DisassemblyDiagnoser(maxDepth: 4, printSource: true, exportGithubMarkdown: true)]
[MemoryDiagnoser(displayGenColumns: false)]
public class JitDisassemblyBenchmark
{
    private TestOrder _order = null!;
    private AcBinarySerializerOptions _fastModeOptions = null!;
    private AcBinarySerializerOptions _defaultOptions = null!;
    private byte[] _serializedFastMode = null!;
    private byte[] _serializedDefault = null!;

    [GlobalSetup]
    public void Setup()
    {
        TestDataFactory.ResetIdCounter();
        var sharedTag = TestDataFactory.CreateTag("SharedTag");
        var sharedUser = TestDataFactory.CreateUser("shareduser");

        // Medium data: enough properties to show loop behavior, not too large for disassembly
        _order = TestDataFactory.CreateOrder(
            itemCount: 3,
            palletsPerItem: 3,
            measurementsPerPallet: 3,
            pointsPerMeasurement: 4,
            sharedTag: sharedTag,
            sharedUser: sharedUser);

        _fastModeOptions = AcBinarySerializerOptions.FastMode;
        _defaultOptions = AcBinarySerializerOptions.Default;
        _serializedFastMode = AcBinarySerializer.Serialize(_order, _fastModeOptions);
        _serializedDefault = AcBinarySerializer.Serialize(_order, _defaultOptions);
    }

    /// <summary>
    /// FastMode serialize — no ref tracking, no string interning.
    /// </summary>
    [Benchmark(Baseline = true)]
    public byte[] Serialize_FastMode()
    {
        return AcBinarySerializer.Serialize(_order, _fastModeOptions);
    }

    /// <summary>
    /// FastMode deserialize.
    /// </summary>
    [Benchmark]
    public TestOrder Deserialize_FastMode()
    {
        return AcBinaryDeserializer.Deserialize<TestOrder>(_serializedFastMode, _fastModeOptions);
    }

    /// <summary>
    /// Default serialize — ref tracking + string interning (scan pass + write pass).
    /// Shows IdentityMap lookup overhead in hot path.
    /// </summary>
    [Benchmark]
    public byte[] Serialize_Default()
    {
        return AcBinarySerializer.Serialize(_order, _defaultOptions);
    }

    /// <summary>
    /// Default deserialize — ref tracking + string interning.
    /// </summary>
    [Benchmark]
    public TestOrder Deserialize_Default()
    {
        return AcBinaryDeserializer.Deserialize<TestOrder>(_serializedDefault, _defaultOptions);
    }
}
