#pragma once

#include "cookie_headers.h"
#include "domain_info.h"
#include "gdpr_controls.h"

#include <balancer/modules/cookie_policy/common/cookie_policy.cfgproto.pb.h>

#include <balancer/kernel/cookie/gdpr/gdpr.h>
#include <balancer/kernel/cookie/gdpr/is_gdpr_b.h>

#include <balancer/kernel/module/conn_descr.h>

namespace NModCookiePolicy {
    using namespace NSrvKernel;
    using namespace NGdprCookie;

    using TExtractedIsGdpr = TExtractedRequestCookie<EIsGdpr>;
    using TExtractedIsGdprB = TExtractedRequestCookie<TIsGdprB>;
    using TExtractedGdpr = TExtractedRequestCookie<EGdpr>;

    [[nodiscard]]
    TExtractedGdpr ExtractGdprCookie(const TVector<TRequestCookie>& cookie) noexcept;

    [[nodiscard]]
    bool HasGdprPopupCookie(const TVector<TRequestCookie>& cookie) noexcept;

    [[nodiscard]]
    TExtractedIsGdpr ExtractIsGdprCookie(const TVector<TRequestCookie>& cookie) noexcept;

    [[nodiscard]]
    TExtractedIsGdprB ExtractIsGdprBCookie(const TVector<TRequestCookie>& cookie) noexcept;

    [[nodiscard]]
    TMaybe<bool> ExtractXYandexEURequest(const THeaders& reqHeaders) noexcept;

    [[nodiscard]]
    TMaybe<TXIpProperties> ExtractXIpProperties(const THeaders& reqHeaders) noexcept;


    struct [[nodiscard]] TGdprLocation {
        bool IsGdpr = false;
        TMaybe<bool> IsGdprNoVpn;
        EGdprSource Source = EGdprSource::None;
        EGdprSource SourceNoVpn = EGdprSource::None;

        Y_BALANCER_TUPLE_EQ(TGdprLocation, IsGdprNoVpn, Source, SourceNoVpn);
    };


    struct TGdprStatus : public TGdpr {
        EGdprSource Source = EGdprSource::None;
        EGdprSource SafeSource = EGdprSource::None;

        Y_BALANCER_TUPLE_EQ(TGdprStatus, std::ref((const TGdpr&)(*this)), Source, SafeSource);
    };


    [[nodiscard]]
    TGdprCache UpdateGdprIpGeoCache(
        TGdprCache ipGeo,
        TMaybe<bool> xYandexEURequest,
        const TGdprControls& cfg,
        const TGdprControls* dynCfg
    ) noexcept;

    struct TGlobalStats;

    struct TReporting {
        IOutputStream& Log;
        TGlobalStats& Stats;
    };


    struct TFilterArgs {
        const TGdprControls& Cfg;
        const TGdprControls* DynCfg = nullptr;
    };


    [[nodiscard]]
    TMaybe<TIsGdprB> FilterAndLogIsGdprB(
        const TExtractedIsGdprB& isGdprB, TInstant now, TFilterArgs args, TReporting reporting) noexcept;


    [[nodiscard]]
    TMaybe<bool> FilterAndLogXYandexEURequest(
        TMaybe<bool> xYandexEURequest, TFilterArgs args, TReporting reporting) noexcept;

    [[nodiscard]]
    TMaybe<TXIpProperties> FilterAndLogXIpProperties(
        TMaybe<TXIpProperties> xIpProperties, TFilterArgs args, TReporting reporting) noexcept;


    [[nodiscard]]
    TMaybe<TGdprLocation> UpdateGdprLocation(
        TGdprCache geo,
        TMaybe<TIsGdprB> isGdprB
    ) noexcept;


    [[nodiscard]]
    TMaybe<TGdprStatus> UpdateGdprStatus(
        TMaybe<EGdpr> gdpr,
        TMaybe<TGdprLocation> loc,
        const TDomainInfo& domainInfo,
        bool gdprPopup,
        TReporting reporting
    ) noexcept;


    [[nodiscard]]
    TMaybe<EIsGdpr> UpdateIsGdpr(TMaybe<TGdprLocation> loc) noexcept;


    [[nodiscard]]
    TMaybe<TIsGdprB> UpdateIsGdprB(TMaybe<TGdprLocation> loc, TInstant now) noexcept;
}
