// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.

using System.Security.Cryptography;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;
using Isopoh.Cryptography.Argon2;
using Konscious.Security.Cryptography;
using Argon2 = Isopoh.Cryptography.Argon2.Argon2;

namespace Benchmarks;

[Orderer(SummaryOrderPolicy.FastestToSlowest)]
[Config(typeof(GenericConfig))]
public class Argon2Benchmarks
{
    [Params(2, 4)] public int _iterations;
    [Params(16, 32)] public int _memory;
    [Params(1, 2)] public int _parallelism;
    private byte[] _salt = null!;
    private byte[] _additionalData = null!;
    [Params(16)] public int _length;

    private byte[] _password = null!;

    [GlobalSetup]
    public void Setup()
    {
        _salt = RandomNumberGenerator.GetBytes(16);
        _additionalData = RandomNumberGenerator.GetBytes(16);
        _password = RandomNumberGenerator.GetBytes(16);
    }

    [Benchmark]
    public byte[] Argon2i()
    {
        return new Argon2i(_password)
        {
            Iterations = _iterations,
            MemorySize = 1024 * _memory,
            DegreeOfParallelism = _parallelism,
            AssociatedData = _additionalData,
            Salt = _salt,
        }.GetBytes(_length);
    }

    [Benchmark]
    public byte[] Argon2d()
    {
        return new Argon2d(_password)
        {
            Iterations = _iterations,
            MemorySize = 1024 * _memory,
            DegreeOfParallelism = _parallelism,
            AssociatedData = _additionalData,
            Salt = _salt,
        }.GetBytes(_length);
    }

    [Benchmark]
    public byte[] Argon2id()
    {
        return new Argon2id(_password)
        {
            Iterations = _iterations,
            MemorySize = 1024 * _memory,
            DegreeOfParallelism = _parallelism,
            AssociatedData = _additionalData,
            Salt = _salt,
        }.GetBytes(_length);
    }

    [Benchmark]
    public byte[] IsopohArgon2DD()
    {
        var config = new Argon2Config
        {
            Type = Argon2Type.DataDependentAddressing,
            Version = Argon2Version.Nineteen,
            MemoryCost = 1024 * _memory,
            TimeCost = _iterations,
            Lanes = _parallelism,
            HashLength = _length,
            Salt = _salt,
            AssociatedData = _additionalData,
            Password = _password,
        };
        var argon2 = new Argon2(config);
        return argon2.Hash().Buffer;
    }

    [Benchmark]
    public byte[] IsopohArgon2DI()
    {
        var config = new Argon2Config
        {
            Type = Argon2Type.DataIndependentAddressing,
            Version = Argon2Version.Nineteen,
            MemoryCost = 1024 * _memory,
            TimeCost = _iterations,
            Lanes = _parallelism,
            HashLength = _length,
            Salt = _salt,
            AssociatedData = _additionalData,
            Password = _password,
        };
        var argon2 = new Argon2(config);
        return argon2.Hash().Buffer;
    }

    [Benchmark]
    public byte[] IsopohArgon2Hybrid()
    {
        var config = new Argon2Config
        {
            Type = Argon2Type.HybridAddressing,
            Version = Argon2Version.Nineteen,
            MemoryCost = 1024 * _memory,
            TimeCost = _iterations,
            Lanes = _parallelism,
            HashLength = _length,
            Salt = _salt,
            AssociatedData = _additionalData,
            Password = _password,
        };
        var argon2 = new Argon2(config);
        return argon2.Hash().Buffer;
    }
}