#pragma once

#include "enums.h"
#include "gdpr.h"
#include "utils.h"

#include <balancer/kernel/cookie/cookie_errors.h>
#include <balancer/kernel/helpers/helper_macro.h>
#include <balancer/kernel/stats/manager.h>

#include <util/generic/string.h>
#include <util/generic/deque.h>

namespace NModCookiePolicy {
    using namespace NSrvKernel;

    TSharedCounter MakeCounter(TVector<TString> id, TSharedStatsManager& manager);

    template <class EEnum>
    struct TValueCounters {
        TDeque<TSharedCounter> Values;

    public:
        TValueCounters(TString prefix, TSharedStatsManager& m)
        {
            for (auto c : xrange(GetEnumItemsCount<EEnum>())) {
                this->Values.emplace_back(MakeCounter({prefix, ToString(EEnum(c))}, m));
            }
            for (auto c : GetEnumAllValues<EEnum>()) {
                Y_VERIFY(Values.size() > ui32(c));
            }
        }

        TValueCounters(const TValueCounters& tmpl, ui32 workerId)
        {
            for (auto& e: tmpl.Values) {
                this->Values.emplace_back(e, workerId);
            }
        }

        void Inc(EEnum val) noexcept {
            this->Values[ui32(val)].Add(1);
        }
    };


    struct TGlobalStats {
        TSharedCounter Total;
        TSharedCounter Off;
        TSharedCounter Checked;
        TSharedCounter ModifiedReq;
        TSharedCounter ModifiedResp;

        TSharedCounter ParserTotal;
        TSharedCounter ParserSkip;
        TSharedCounter ParserPass;
        TSharedCounter ParserFail;
        TSharedCounter ParserFix;
        TSharedCounter ParserFixDryRun;

        TSharedCounter ParserCookieTotal;
        TSharedCounter ParserCookiePass;
        TSharedCounter ParserCookieFail;
        TSharedCounter ParserCookieDrop;
        TSharedCounter ParserCookieDropDryRun;

        TSharedCounter GdprCookie;
        TSharedCounter GdprConflict;
        TSharedCounter GdprBadValue;

        TSharedCounter GdprPopup;
        TSharedCounter GdprPopupNoGdpr;

        TSharedCounter IsGdprCookie;
        TSharedCounter IsGdprDuplicate;
        TSharedCounter IsGdprBadValue;

        TSharedCounter IsGdprBCookie;
        TSharedCounter IsGdprBFiltered;
        TSharedCounter IsGdprBDuplicate;
        TSharedCounter IsGdprBBadValue;
        TSharedCounter IsGdprBOff;

        TSharedCounter XYandexEURequest;
        TSharedCounter XYandexEURequestOff;

        TSharedCounter XIpProperties;
        TSharedCounter XIpPropertiesOff;

        TSharedCounter GdprDomain;

    public:
        TGlobalStats(TString uuid, TSharedStatsManager& manager);
        TGlobalStats(const TGlobalStats& tmpl, ui32 workerId);

        void IncParserErrors(TSetCookieSyntaxErrors errs) noexcept;
        void IncGdpr(TGdprStatus v) noexcept;

        void OnGdpr(const TExtractedGdpr&) noexcept;
        void OnIsGdpr(const TExtractedIsGdpr&) noexcept;
        void OnIsGdprB(const TExtractedIsGdprB&) noexcept;

    private:
        TValueCounters<ESetCookieSyntaxError> ParserErrors_;

        TValueCounters<EIsGdpr> GdprGeo_;
        TValueCounters<EGdpr> GdprMod_;
        TValueCounters<EGdprSource> GdprSrc_;
        TValueCounters<EIsGdpr> GdprSafeGeo_;
        TValueCounters<EGdpr> GdprSafeMod_;
        TValueCounters<EGdprSource> GdprSafeSrc_;
    };


    struct TPolicyStats {
        TSharedCounter Total;
        TSharedCounter Off;
        TSharedCounter Pass;
        TSharedCounter Fail;
        TSharedCounter Fix;
        TSharedCounter FixDryRun;

        TPolicyStats(TString uuid, TSharedStatsManager& manager);
        TPolicyStats(const TPolicyStats& tmpl, ui32 workerId);

        void OnFail(bool dryRun) noexcept;
    };


    struct TPolicyCookieStats {
        TSharedCounter ReqCookieDrop;
        TSharedCounter ReqCookieFix;
        TSharedCounter ReqCookieAdd;
        TSharedCounter ReqCookieDropDryRun;
        TSharedCounter ReqCookieFixDryRun;
        TSharedCounter ReqCookieAddDryRun;

        TSharedCounter CookieTotal;
        TSharedCounter CookieSkip;
        TSharedCounter CookiePass;
        TSharedCounter CookieFail;
        TSharedCounter CookieDrop;
        TSharedCounter CookieFix;
        TSharedCounter CookieAdd;
        TSharedCounter CookieDropDryRun;
        TSharedCounter CookieFixDryRun;
        TSharedCounter CookieAddDryRun;

        TPolicyCookieStats(TString uuid, TSharedStatsManager& manager);
        TPolicyCookieStats(const TPolicyCookieStats& tmpl, ui32 workerId);
    };
}
