namespace SharpChat;

public class RateLimiter {
    public const int DEFAULT_SIZE = 30;
    public const int DEFAULT_MINIMUM_DELAY = 10000;
    public const int DEFAULT_RISKY_OFFSET = 5;

    private readonly int Size;
    private readonly int MinimumDelay;
    private readonly int RiskyOffset;
    private readonly long[] TimePoints;

    public RateLimiter(
        int size = DEFAULT_SIZE,
        int minDelay = DEFAULT_MINIMUM_DELAY,
        int riskyOffset = DEFAULT_RISKY_OFFSET
    ) {
        if(size < 2)
            throw new ArgumentException("Size is too small.", nameof(size));
        if(minDelay < 1000)
            throw new ArgumentException("Minimum delay is inhuman.", nameof(minDelay));
        if(riskyOffset != 0) {
            if(riskyOffset >= size)
                throw new ArgumentException("Risky offset may not be greater or equal to the size.", nameof(riskyOffset));
            else if(riskyOffset < 0)
                throw new ArgumentException("Risky offset may not be negative.", nameof(riskyOffset));
        }

        Size = size;
        MinimumDelay = minDelay;
        RiskyOffset = riskyOffset;
        TimePoints = new long[Size];
    }

    public bool IsRisky => TimePoints[RiskyOffset] != 0 && TimePoints[RiskyOffset + 1] != 0 && TimePoints[RiskyOffset] + MinimumDelay >= TimePoints[Size - 1];
    public bool IsExceeded => TimePoints[0] != 0 && TimePoints[1] != 0 && TimePoints[0] + MinimumDelay >= TimePoints[Size - 1];

    public void Update() {
        for(int i = 1; i < Size; ++i)
            TimePoints[i - 1] = TimePoints[i];
        TimePoints[Size - 1] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
    }
}