#pragma once

#include "complex_factors.h"
#include "geo_block.h"
#include "zone.h"

#include <library/cpp/int128/int128.h>

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

#include <util/memory/blob.h>
#include <util/datetime/base.h>
#include <util/generic/string.h>
#include <util/generic/vector.h>

namespace NSaas {
    class TDocument: public TAbstractZone {
        friend class TProtobufDeserializer;
    public:
        typedef TDocument TThis;

    public:
        TDocument(NRTYServer::TMessage::TDocument& document);
        void BuildJsonMessage(NJson::TJsonValue& result) const;
        NJson::TJsonValue ToJson(TToJsonContext& context) const override;

        /*(Get|Set|Has)Realtime*/   PROTOBUF_FIELD_ACCESSORS(bool, Realtime, InternalDocument, Realtime)
        /*(Get|Set|Has)CheckOnlyBeforeReply*/   PROTOBUF_FIELD_ACCESSORS(bool, CheckOnlyBeforeReply, InternalDocument, CheckOnlyBeforeReply)
        /*(Get|Set|Has)DeadlineMinutesUTC*/     PROTOBUF_FIELD_ACCESSORS(ui32, DeadlineMinutesUTC, InternalDocument, DeadlineMinutesUTC)
        /*(Get|Set|Has)StreamId*/   PROTOBUF_FIELD_ACCESSORS(ui32, StreamId, InternalDocument, StreamId)
        /*(Get|Set|Has)Timestamp*/  PROTOBUF_FIELD_ACCESSORS(ui32, Timestamp, InternalDocument, ModificationTimestamp)
        /*(Get|Set|Has)Version*/    PROTOBUF_FIELD_ACCESSORS(ui32, Version, InternalDocument, Version)
        /*(Get|Set|Has)Version*/    PROTOBUF_FIELD_ACCESSORS(ui32, VersionTimestamp, InternalDocument, VersionTimestamp)
        /*(Get|Set|Has)FilterRank*/ PROTOBUF_FIELD_ACCESSORS(double, FilterRank, InternalDocument, FilterRank)
        /*(Get|Set|Has)DatabaseVersion*/PROTOBUF_FIELD_ACCESSORS(ui32, DatabaseVersion, InternalDocument, DatabaseVersion)
        /*(Get|Set|Has)UpdateType*/ PROTOBUF_FIELD_ACCESSORS(NRTYServer::TMessage::TUpdateType, UpdateType, InternalDocument, UpdateType)
        /*(Get|Set|Has)MimeType*/   PROTOBUF_FIELD_ACCESSORS_REF(TString, MimeType, InternalDocument, MimeType)
        /*(Get|Set|Has)Charset*/    PROTOBUF_FIELD_ACCESSORS_REF(TString, Charset, InternalDocument, Charset)
        /*(Get|Set|Has)Lang*/       PROTOBUF_FIELD_ACCESSORS_REF(TString, Lang, InternalDocument, Language)
        /*(Get|Set|Has)Lang2*/      PROTOBUF_FIELD_ACCESSORS_REF(TString, Lang2, InternalDocument, Language2)
        /*(Get|Set|Has)LangDef*/    PROTOBUF_FIELD_ACCESSORS_REF(TString, LangDef, InternalDocument, LanguageDefault)
        /*(Get|Set|Has)Url*/        PROTOBUF_FIELD_ACCESSORS_REF(TString, Url, InternalDocument, Url)
        /*(Get|Set|Has)Text*/       PROTOBUF_FIELD_ACCESSORS_REF(TString, Text, InternalDocument, Body)
        /*(Get|Set|Has)Body*/       PROTOBUF_FIELD_ACCESSORS_REF(TString, Body, InternalDocument, Body)
        /*(Get|Set|Has)Annotations*/PROTOBUF_PBFIELD_ACCESSORS(NRTYServer::TMessage::TAnnData, Annotations, InternalDocument, AnnData)
        /*(Get|Set|Has)GeoData*/    PROTOBUF_PBFIELD_ACCESSORS(NRTYServer::TMessage::TGeoData, GeoData, InternalDocument, GeoData)
        /*(Get|Set|Has)IndexedDoc*/ PROTOBUF_PBFIELD_ACCESSORS(NRealTime::TIndexedDoc, IndexedDoc, InternalDocument, IndexedDoc)
        TString& MutableText() {
            return * InternalDocument.MutableBody();
        }
        const TString& GetName() const override {
            return Default<TString>();
        }

        TInstant GetDeadline() const;
        TDocument& SetDeadline(TInstant value);

        TCSBlock& AddCS(const TString& name);
        TQSBlock& AddQS(const TString& name);
        TIntQSBlock& AddIntQS(const TString& name);
        TAnnBlock& AddAnnotations();
        TGeoBlock& AddGeo();
        TDocument& AddFactor(const TString& name, float value);
        TDocument& AddIntFactor(const TString& name, i32 value);
        TDocument& AddProperty(const TString& name, const TString& value);
        TDocument& AddEmbedding(const TString& name, TStringBuf value, TStringBuf version={}, TStringBuf tag = {});

        template <class T>
        TDocument& AddProperty(const TString& name, const T& value) {
            AddProperty(name, ToString(value));
            return *this;
        }

        template <class T>
        TDocument& AddSpecialKey(const TString& name, const T& value) {
            AddSpecialKey(name, ToString(value));
            return *this;
        }

        TDocument& AddSpecialKey(const TString& name, const TString& value);
        TDocument& AddTrigramIndexingProp(const TString& name, const TString& value);
        TDocument& AddBinaryProperty(const TString& name, const TString& value);
        TDocument& AddFSProperty(const TString& name, const TString& value);
        TDocument& AddGroupAttribute(const TString& name, i64 value);
        TDocument& AddGroupAttribute(const TString& name, const TString& value);
        TDocument& AddExtraTimestamp(ui32 stream, ui128 value);
        TDocument& AddObjectContext(const TString& serialized);

        NRTYServer::TMessage::TQSInfo& AddQSInfo() {
            return * InternalDocument.AddQSInfo();
        }
        // deprecated
        const TString& GetLangDef2() const {
            return Default<TString>();
        }
        // deprecated
        TDocument& SetLangDef2(const char* value) {
            Y_UNUSED(value);
            return *this;
        }
    protected:
        virtual NRTYServer::TZone& AddSubZone() override {
            return * InternalDocument.MutableRootZone()->AddChildren();
        }

        virtual void OnAttribute(const TString& name, const TString& value, TAttributeValue::TAttributeValueType type) override;

    private:
        TVector<TSimpleSharedPtr<TCSBlock> > CSBlocks;
        TVector<TSimpleSharedPtr<TQSBlock> > QSBlocks;
        TVector<TSimpleSharedPtr<TIntQSBlock> > IntQSBlocks;
        THolder<TAnnBlock> Annotations;
        THolder<TGeoBlock> GeoBlock;

        NRTYServer::TMessage::TDocument& InternalDocument;
    };
}
