using System.Security.Cryptography;

namespace StellaOps.Feedser.Source.Common.Fetch;

/// <summary>
/// Jitter source backed by <see cref="RandomNumberGenerator"/> for thread-safe, high-entropy delays.
/// </summary>
public sealed class CryptoJitterSource : IJitterSource
{
    public TimeSpan Next(TimeSpan minInclusive, TimeSpan maxInclusive)
    {
        if (maxInclusive < minInclusive)
        {
            throw new ArgumentException("Max jitter must be greater than or equal to min jitter.", nameof(maxInclusive));
        }

        if (minInclusive < TimeSpan.Zero)
        {
            minInclusive = TimeSpan.Zero;
        }

        if (maxInclusive == minInclusive)
        {
            return minInclusive;
        }

        var minTicks = minInclusive.Ticks;
        var maxTicks = maxInclusive.Ticks;
        var range = maxTicks - minTicks;

        Span<byte> buffer = stackalloc byte[8];
        RandomNumberGenerator.Fill(buffer);
        var sample = BitConverter.ToUInt64(buffer);
        var ratio = sample / (double)ulong.MaxValue;
        var jitterTicks = (long)Math.Round(range * ratio, MidpointRounding.AwayFromZero);
        if (jitterTicks > range)
        {
            jitterTicks = range;
        }

        return TimeSpan.FromTicks(minTicks + jitterTicks);
    }
}
