#pragma once

#include "grouping.h"

#include <search/session/compression/methods/methods.h>

#include <library/cpp/json/json_value.h>

#include <util/datetime/base.h>
#include <util/generic/string.h>
#include <util/generic/vector.h>
#include <util/generic/set.h>
#include <util/generic/maybe.h>

namespace NSaas {

    class TQuery {
    private:
        TString Kps;
        TString UserId;
        TVector<TString> Texts;
        TString QTree;
        TGrouping Grouping;
        TString GTA;
        TString Auth;
        TString KeyName;
        TSortPolicy How;
        bool Ascending = false;
        bool Priority = false;
        bool NeedInSnippet = false;
        bool HrAnswer = false;
        bool IsSuggest = false;
        bool JsonFactors = false;
        bool SkipSearcherProps = false;
        bool KeyValue = false;
        bool SplitText = false;
        bool NormalKVReport = true;
        bool IsGroupingDisabled = false;
        ui32 Page = 0;
        ui32 NumDoc = 10;
        TVector<TString> Properties;
        TVector<TString> Relev;
        TSet<TString> PronFlags;
        TString WizardRules;
        TString ExtraParams;
        TString CustomPathPrefix;
        NMetaProtocol::ECompressionMethod CompressionMethod = NMetaProtocol::CM_COMPRESSION_NONE;
        TMaybe<TDuration> BalancerTimeout;
        THashMap<TString, TString> Headers;

    private:
        template <class TSerializer>
        void SerializeQuery(TSerializer& s) const;

    public:
        TQuery() = default;

        TQuery& SetKps(const TString& Value) {
            Kps = Value;
            return *this;
        }

        TQuery& SetText(const TString& Value) {
            Texts.resize(1);
            Texts[0] = Value;
            return *this;
        }

        TQuery& AddText(const TString& Value) {
            Texts.push_back(Value);
            return *this;
        }

        TQuery& SetAuth(const TString& Value) {
            Auth = Value;
            return *this;
        }

        TQuery& SetUserId(const TString& Value) {
            UserId = Value;
            return *this;
        }

        TQuery& SetHrAnswer(bool Value) {
            HrAnswer = Value;
            return *this;
        }

        TQuery& SetSuggest(bool Value) {
            IsSuggest = Value;
            return *this;
        }

        TQuery& SetNeedInSnippet(bool Value) {
            NeedInSnippet = Value;
            return *this;
        }

        TQuery& SetNumDoc(ui32 Value) {
            NumDoc = Value;
            return *this;
        }

        TQuery& SetAscending(bool Value) {
            Ascending = Value;
            return *this;
        }

        TQuery& SetPriority(bool Value) {
            Priority = Value;
            return *this;
        }

        TQuery& SetJsonFactors(bool Value) {
            JsonFactors = Value;
            return *this;
        }

        TQuery& SetSkipSearcherProps(bool Value) {
            SkipSearcherProps = Value;
            return *this;
        }

        TQuery& SetPage(ui32 Value) {
            Page = Value;
            return *this;
        }

        TQuery& SetQTree(const TString& Value) {
            QTree = Value;
            return *this;
        }

        TQuery& AddProperty(const TString& Name) {
            Properties.push_back(Name);
            return *this;
        }

        TQuery& AddRelev(const TString& Value) {
            Relev.push_back(Value);
            return *this;
        }

        TQuery& AddPron(const TString& Name) {
            PronFlags.insert(Name);
            return *this;
        }

        TQuery& SetWizardRules(const TString& wizardRules) {
            WizardRules = wizardRules;
            return *this;
        }

        TQuery& SetExtraParams(const TString& params) {
            ExtraParams = params;
            return *this;
        }

        TQuery& SetCustomPathPrefix(const TString& customPathPrefix) {
            CustomPathPrefix = customPathPrefix;
            return *this;
        }

        TQuery& SetCompressionMethod(NMetaProtocol::ECompressionMethod method) {
            CompressionMethod = method;
            return *this;
        }

        TGrouping& GroupingBuilder() {
            return Grouping;
        }

        TSortPolicy& HowBuilder() {
            return How;
        }

        TQuery& SetKeyValue() {
            KeyValue = true;
            return *this;
        }

        TQuery& SetSplitText() {
            SplitText = true;
            return *this;
        }

        TQuery& SetNotNormalKVReport() {
            NormalKVReport = false;
            return *this;
        }

        TQuery& SetKeyName(const TString& keyName) {
            KeyName = keyName;
            return *this;
        }

        TQuery& SetBalancerTimeout(TDuration timeout) {
            BalancerTimeout = timeout;
            return *this;
        }

        TMaybe<TDuration> GetBalancerTimeout() const {
            return BalancerTimeout;
        }

        TQuery& AddHeader(TString key, TString value) {
            Headers.emplace(key, value);
            return *this;
        }

        const THashMap<TString, TString>& GetHeaders() const {
            return Headers;
        }

        TVector<TString>& GetRelev() {
            return Relev;
        }

        TSet<TString>& GetPron() {
            return PronFlags;
        }

        TQuery& DisableGrouping() {
            IsGroupingDisabled = true;
            return *this;
        }

        TString BuildQuery() const;
        NJson::TJsonValue BuildAppHostQuery(const TString& service) const;
        bool ValidateQuery() const;
    };

}
