#pragma once

#include <util/generic/algorithm.h>
#include <util/datetime/base.h>

#include <utility>

namespace NSrvKernel {
    template <size_t N>
    class TTimeLimitedAvgTracker {
    public:
        TTimeLimitedAvgTracker(TDuration ttl) noexcept
            : Ttl_(ttl)
        {}

        std::pair<double, size_t> Get() const noexcept {
            Check();
            return std::pair<double, size_t>(Sum_, Total_);
        }

        double M() const noexcept {
            Check();
            return Total_ ? Sum_ / Total_ : 1.;
        }

        TInstant StartT() const noexcept {
            if (Total_ == 0) {
                return Now();
            } else {
                return T_[Cur_];
            }
        }

        void Add(double v) noexcept {
            TInstant now = Now();

            if (Total_ == N) {
                Sum_ = Sum_ + v - V_[Cur_];
                V_[Cur_] = v;
                T_[Cur_] = now;
                Cur_ = (Cur_ + 1) % N;
            } else {
                const size_t l = (Cur_ + Total_) % N;
                V_[l] = v;
                T_[l] = now;
                Sum_ += v;
                Total_ += 1;
            }
        }

        void SetTtl(const TDuration& ttl) noexcept {
            Ttl_ = ttl;
        }

    private:
        void Check() const noexcept {
            TInstant now = Now();

            while (Total_ != 0) {
                if (now - T_[Cur_] > Ttl_) {
                    Sum_ -= V_[Cur_];
                    Total_ -= 1;
                    Cur_ = (Cur_ + 1) % N;
                } else {
                    break;
                }
            }
        }

    private:
        double V_[N];
        TInstant T_[N];
        mutable size_t Cur_ = 0;
        mutable size_t Total_ = 0;
        mutable double Sum_ = 0.;

        TDuration Ttl_;
    };
}
