#pragma once

#include <util/generic/deque.h>
#include <util/system/types.h>
#include <util/datetime/base.h>
#include <util/generic/vector.h>
#include <util/system/mutex.h>

#include <functional>
#include <optional>

class TStatsBuffer {
public:
    using TStats = TVector<ui64>;
    using TReadVisitor = std::function<void(const TStats&)>;
    using TWriteVisitor = std::function<void(TStats&)>;

    // all Max-durations must be divisible by interval
    TStatsBuffer(TInstant start, size_t valuesPerInterval, TDuration interval, TDuration maxStatsAge, TDuration maxWriteAge);

    bool VisitReadableStats(TInstant currentTime, TInstant readTime, TReadVisitor visitor) const;
    bool VisitWritableStats(TInstant currentTime, TInstant writeTime, TWriteVisitor visitor);

private:
    bool VisitStats(TInstant currentTime, TInstant time, TWriteVisitor visitor, std::function<bool()> checkTimeRestrictions);

    void Advance(TInstant currentTime);

    void AddInterval(std::optional<TInstant> intervalEnd = std::nullopt);

    // Writable intervals have absolute values (e.g. hits during the interval).
    // Once they turn into readable, they will have all previous values added up
    // from all the preceding intervals. This is required for RATE sensor to work.
    // The process of adding previous values here is called Baking.

    // TODO: Disabled as we are currently using IGAUGE instead of RATE
    void BakeInterval(size_t pos);

    TInstant IntervalUpperBoundary(TInstant instant);

private:
    TMutex Lock_;

    // the interval is right-open and does not contain LastIntervalEnd_ point
    TInstant LastIntervalEnd_;
    TDeque<TStats> StatsIntervals_;

public:
    const TDuration MaxStatsAge;
    // do not update stats if they are more than MaxWriteAge_
    // in the past. Must be lower than MinReadAge_
    const TDuration MaxWriteAge;
    const TDuration Interval;

    const size_t ValuesPerInterval;
};
