#pragma once

#include <util/generic/xrange.h>

#include <algorithm>
#include <array>

namespace NSrvKernel {

    struct TConnStats {
        size_t ConnRefused = 0;
        size_t ConnTimeout = 0;
        size_t ConnOtherError = 0;
        size_t NoBackendsError = 0;
        size_t ClientTimeout = 0;
        size_t BackendTimeout = 0;
        size_t BackendAttempt = 0;
        size_t LimitedBackendAttempt = 0;
        size_t BackendError = 0;
        size_t ClientError = 0;
        size_t Code503 = 0;
        size_t BackendKeepaliveReused = 0;
        std::array<size_t, 5> StatusCodes = {};
        size_t BackendHedgedAttempts = 0;
        size_t BackendHedgedSucc = 0;
        size_t BackendWriteError = 0;
        size_t BackendShortReadAnswer = 0;

    public:
        void OnStatusCode(unsigned status) noexcept {
            if (503 == status) {
                Code503 += 1;
            }
            StatusCodes[std::min<unsigned>(status, 599) / 100 - 1] += 1;
        }

        bool HasConnError() const noexcept {
            return ConnRefused || ConnTimeout || ConnOtherError || NoBackendsError;
        }

        TConnStats friend operator-(const TConnStats& curr, const TConnStats& prev) noexcept {
            TConnStats res;
#define Y_CONN_STATS_DELTA(field) res.field = curr.field - prev.field;
            Y_CONN_STATS_DELTA(ConnRefused);
            Y_CONN_STATS_DELTA(ConnTimeout);
            Y_CONN_STATS_DELTA(ConnOtherError);
            Y_CONN_STATS_DELTA(NoBackendsError);
            Y_CONN_STATS_DELTA(ClientTimeout);
            Y_CONN_STATS_DELTA(BackendTimeout);
            Y_CONN_STATS_DELTA(BackendAttempt);
            Y_CONN_STATS_DELTA(LimitedBackendAttempt);
            Y_CONN_STATS_DELTA(BackendError);
            Y_CONN_STATS_DELTA(ClientError);
            Y_CONN_STATS_DELTA(Code503);
            Y_CONN_STATS_DELTA(BackendKeepaliveReused);
            Y_CONN_STATS_DELTA(BackendHedgedAttempts);
            Y_CONN_STATS_DELTA(BackendHedgedSucc);
            Y_CONN_STATS_DELTA(BackendWriteError);
            Y_CONN_STATS_DELTA(BackendShortReadAnswer);
            for (auto i : xrange(res.StatusCodes.size())) {
                Y_CONN_STATS_DELTA(StatusCodes[i]);
            }
#undef Y_CONN_STATS_DELTA

            return res;
        }
    };

}
