#pragma once

#include "fix_interval.h"

#include <library/cpp/unistat/unistat.h>
#include <library/cpp/json/writer/json_value.h>

#include <util/generic/vector.h>
#include <util/generic/string.h>
#include <library/cpp/deprecated/atomic/atomic.h>
#include <util/system/rwlock.h>

class TTimeSlidedHistogram {
private:
    TVector<TFixIntervalHistogram::TPtr> TimeBuckets;
    TVector<ui32> BucketId;
    const ui32 SecondsDuration;
    const ui32 SegmentsCount;
    TAtomic CurrentId = 0;
    TRWMutex Mutex;

public:
    class TGuard {
    private:
        TTimeSlidedHistogram* Histogram;
        const TInstant StartTime = Now();
    public:
        TGuard(TTimeSlidedHistogram& histogram)
            : Histogram(&histogram)
        {
        }

        ~TGuard() {
            Release();
        }

        void Release() {
            if (Histogram) {
                Histogram->Add((Now() - StartTime).Seconds());
                Histogram = nullptr;
            }
        }
    };

public:
    TTimeSlidedHistogram(const ui32 segmentsCount, const ui32 secondsDuration, const double min, const double max, const ui32 segmentsCountHistogram);

    TString GetIntervalName(const ui32 index) const {
        return TimeBuckets[0]->GetIntervalName(index);
    }

    void Add(const double value);
    TVector<ui32> Clone() const;
    NJson::TJsonValue GetReport() const;
};

class TTSHistogramAndTASS: public TTimeSlidedHistogram, public TNonCopyable {
private:
    NUnistat::TIntervals Intervals;
    const TString Name;

public:
    TTSHistogramAndTASS(const ui32 segmentsCount, const ui32 secondsDuration, const double min, const double max, const ui32 segmentsCountHistogram, const TString& name);

    void Add(const double value) {
        TTimeSlidedHistogram::Add(value);
        TUnistat::Instance().PushSignalUnsafe(Name, value);
    }

    void Init(TUnistat& unistat) const;
};
