#pragma once

#include <util/generic/vector.h>
#include <util/generic/utility.h>
#include <util/generic/yexception.h>

namespace NSaas {
    // A nice rounding routine for the Confidence Interval. The routine ensures consistency of the output in face of fluctuations
    class TCoarser final {
    public:
        // Main method
        static std::pair<i64, i64> GetScaleDivision(i64 sAvg, i64 sDelta, ui64 maxPrec);

    private:
        struct TInterval {
            ui64 Min;
            ui64 Max;

            bool Includes(ui64 p) const {
                return Min <= p && p < Max;
            }

            bool IsEmpty() const {
                return !Length();
            }

            static TInterval Empty() {
                return TInterval{0, 0};
            }

            TInterval Intersect(const TInterval& o) const {
                if (o.Min >= Max || o.Max <= Min)
                    return Empty();
                return TInterval{::Max(o.Min, Min), ::Min(o.Max, Max)};
            }

            ui64 Length() const {
                return Max - Min;
            }
        };

        Y_FORCE_INLINE static ui64 GetCoarsePoint(ui64 p, ui64 scale) {
            return p / scale * scale;
        }

        Y_FORCE_INLINE static TInterval GetCoarseInterval(ui64 p, ui64 scale) {
            TInterval v;
            v.Min = GetCoarsePoint(p, scale);
            v.Max = v.Min + scale;
            return v;
        }

    private:
        static std::pair<TInterval, ui64> OuterCoarse(const TInterval ci, const std::vector<ui64>& scales, const ui64 endLevel);

        static TInterval SmartCoarse(const TInterval ci, const std::vector<ui64>& scales, const ui64 endLevel);

    private:
        static const std::vector<ui64> Scales;
    };
}
