using System;

using StellaOps.Scanner.Worker.Options;

namespace StellaOps.Scanner.Worker.Processing;

public sealed class PollDelayStrategy
{
    private readonly ScannerWorkerOptions.PollingOptions _options;
    private TimeSpan _currentDelay;

    public PollDelayStrategy(ScannerWorkerOptions.PollingOptions options)
    {
        _options = options ?? throw new ArgumentNullException(nameof(options));
    }

    public TimeSpan NextDelay()
    {
        if (_currentDelay == TimeSpan.Zero)
        {
            _currentDelay = _options.InitialDelay;
            return ApplyJitter(_currentDelay);
        }

        var doubled = _currentDelay + _currentDelay;
        _currentDelay = doubled < _options.MaxDelay ? doubled : _options.MaxDelay;
        return ApplyJitter(_currentDelay);
    }

    public void Reset() => _currentDelay = TimeSpan.Zero;

    private TimeSpan ApplyJitter(TimeSpan duration)
    {
        if (_options.JitterRatio <= 0)
        {
            return duration;
        }

        var maxOffset = duration.TotalMilliseconds * _options.JitterRatio;
        if (maxOffset <= 0)
        {
            return duration;
        }

        var offset = (Random.Shared.NextDouble() * 2.0 - 1.0) * maxOffset;
        var adjustedMs = Math.Max(0, duration.TotalMilliseconds + offset);
        return TimeSpan.FromMilliseconds(adjustedMs);
    }
}
