namespace Benchmarks;

using System.Security.Cryptography;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;

[Orderer(SummaryOrderPolicy.FastestToSlowest)]
[Config(typeof(GenericConfig))]
public class BinaryConversionBenchmarks
{
    private byte[] _data = null!;
    private int _offset;
    private int _writeBuffer;

    [GlobalSetup]
    public void Setup()
    {
        this._data = RandomNumberGenerator.GetBytes(4000);
        this._offset = RandomNumberGenerator.GetInt32(0, 3500);
        this._writeBuffer = RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue);
    }

    [Benchmark]
    public short BitConverterParseTest() => BitConverter.ToInt16(this._data, this._offset);

    [Benchmark]
    public short BinaryReader()
    {
        using var ms = new MemoryStream(this._data);
        using var reader = new BinaryReader(ms);
        reader.BaseStream.Position = this._offset;
        return reader.ReadInt16();
    }

    [Benchmark]
    public short BinaryPrimitivesRead() =>
        System.Buffers.Binary.BinaryPrimitives.ReadInt16LittleEndian(
            new ArraySegment<byte>(this._data, this._offset, sizeof(short)));

    [Benchmark]
    public void BinaryPrimitivesWrite()
    {
        System.Buffers.Binary.BinaryPrimitives.WriteInt32LittleEndian(this._data.AsSpan(_offset, 4),
            this._writeBuffer);
    }

    [Benchmark]
    public void BitConverterCopy()
    {
        BitConverter.GetBytes(this._writeBuffer).CopyTo(this._data, this._offset);
    }

    [Benchmark]
    public void BitConverterAssignment()
    {
        var bytes = BitConverter.GetBytes(this._writeBuffer);
        this._data[this._offset] = bytes[0];
        this._data[this._offset + 1] = bytes[1];
        this._data[this._offset + 2] = bytes[2];
        this._data[this._offset + 3] = bytes[3];
    }
}