#include "stats.h"

using namespace NSrvKernel;

namespace {
    TString GetErrorDescription(int errorCode) {
        static const TStringBuf BR_SSL_ROUTINES = ":SSL routines:";

        char* error = ERR_error_string(errorCode, nullptr);
        TStringBuf errorText(error);

        const auto pos = errorText.find(BR_SSL_ROUTINES);
        if (pos == TStringBuf::npos) {
            return {};
        }

        const size_t descriptionStartPos = pos + BR_SSL_ROUTINES.size();
        TString description;
        description.reserve(errorText.size() - descriptionStartPos);
        for (size_t i = descriptionStartPos; i < errorText.size(); ++i) {
            switch (errorText[i]) {
                case ':':
                case ' ':
                    description.push_back('_');
                    break;
                case '(':
                case ')':
                    break;
                default:
                    description.push_back(errorText[i]);
                    break;
            }
        }

        return description;
    }
}

namespace NSsl {

    TSharedCounter* TSslErrorStats::GetCounter(int errorCode, TSharedStatsManager& statsManager, size_t id) {
        if (Counters_.find(errorCode) == Counters_.end()) {
            TString errorDescription = GetErrorDescription(errorCode);
            auto counter = statsManager.GetExistingCounter("ssl_error-" + errorDescription, /*labels =*/ {}, id);
            if (counter) {
                Counters_[errorCode] = MakeHolder<TSharedCounter>(std::move(*counter));
            }
        }

        return Counters_[errorCode].Get();
    }

    void TStats::RegisterError(int errorCode) {
        NSrvKernel::TSharedCounter* counter = TSslErrorStats::Instance().GetCounter(errorCode, StatsManager_, Id_);
        if (counter) {
            counter->Inc();
        }

        ++Errors[errorCode];
        ++ErrorsTotal;

        if (errorCode == 0) {
            ++ZeroErrors;
        }
    }

    TStats::TStats(NSrvKernel::TSharedCounter emptyRequests, NSrvKernel::TSharedCounter httpsRequests,
                   NSrvKernel::TSharedCounter httpRequests, NSrvKernel::TSharedCounter droppedExperiments,
                   NSrvKernel::TSharedCounter errorsTotal, NSrvKernel::TSharedCounter zeroErrors,
                   NFH::TFlatHashMap<EProtocolVersion, THolder<NSrvKernel::TSharedCounter>>& protocolVersions,
                   NSrvKernel::TSharedStatsManager& statsManager, size_t workerId) noexcept
        : Errors{}
        , ProtocolVersions{}
        , EmptyRequests(std::move(emptyRequests))
        , HttpsRequests(std::move(httpsRequests))
        , HttpRequests(std::move(httpRequests))
        , DroppedExperiments(std::move(droppedExperiments))
        , ErrorsTotal(std::move(errorsTotal))
        , ZeroErrors(std::move(zeroErrors))
        , Id_(workerId)
        , StatsManager_(statsManager)
    {
        ProtocolVersions.reserve(GetEnumItemsCount<EProtocolVersion>());
        for (const auto e : GetEnumAllValues<EProtocolVersion>()) {
            ProtocolVersions[e] = MakeHolder<TSharedCounter>(*protocolVersions[e], Id_);
        }
    }
}
