#pragma once
#include <saas/protos/rtyserver.pb.h>
#include <search/idl/meta.pb.h>
#include <util/generic/string.h>
#include <util/generic/vector.h>
#include <util/generic/hash.h>
#include <util/datetime/base.h>
#include <util/string/cast.h>
#include <util/generic/set.h>

class TSearchProtoHelper {
private:
    NMetaProtocol::TDocument& DocOrigin;
public:
    TSearchProtoHelper(NMetaProtocol::TDocument& docOrigin)
        : DocOrigin(docOrigin) {

    }

    template <class T>
    void AddProperty(const TString& name, const T& value) {
        auto* prop = DocOrigin.MutableArchiveInfo()->AddGtaRelatedAttribute();
        prop->SetKey(name);
        prop->SetValue(::ToString(value));
    }
};

class TReadSearchProtoHelper {
private:
    const NMetaProtocol::TDocument& DocOrigin;
public:
    TReadSearchProtoHelper(const NMetaProtocol::TDocument& docOrigin)
        : DocOrigin(docOrigin) {

    }

    template <class T>
    bool GetProperties(const TSet<TString>& names, TMap<TString, T>& value) {
        value.clear();
        for (ui32 prop = 0; prop < DocOrigin.GetArchiveInfo().GtaRelatedAttributeSize(); ++prop) {
            const TString& name = DocOrigin.GetArchiveInfo().GetGtaRelatedAttribute(prop).GetKey();
            if (names.contains(name)) {
                value[name] = FromString<T>(DocOrigin.GetArchiveInfo().GetGtaRelatedAttribute(prop).GetValue());
            }
        }
        return value.size();
    }

    template <class T>
    bool GetProperty(const TString& name, T& value) {
        for (ui32 prop = 0; prop < DocOrigin.GetArchiveInfo().GtaRelatedAttributeSize(); ++prop) {
            if (DocOrigin.GetArchiveInfo().GetGtaRelatedAttribute(prop).GetKey() == name) {
                value = FromString<T>(DocOrigin.GetArchiveInfo().GetGtaRelatedAttribute(prop).GetValue());
                return true;
            }
        }
        return false;
    }
};

class TRTYProtoHelper {
private:
    const NRTYServer::TMessage::TDocument& DocOrigin;
    THashMap<TString, TVector<TString>> Properties;

    void BuildInternalInfo() {
        for (ui32 i = 0; i < DocOrigin.DocumentPropertiesSize(); ++i) {
            auto& prop = DocOrigin.GetDocumentProperties(i);
            Properties[prop.GetName()].push_back(prop.GetValue());
        }
    }
public:
    TRTYProtoHelper(const NRTYServer::TMessage::TDocument& docOrigin)
        : DocOrigin(docOrigin)
    {
        BuildInternalInfo();
    }

    TRTYProtoHelper(const NRTYServer::TMessage& messageOrigin)
        : DocOrigin(messageOrigin.GetDocument())
    {
        BuildInternalInfo();
    }

    const NRTYServer::TMessage::TDocument* operator->() const {
        return &DocOrigin;
    }

    TString DebugString() const {
        return DocOrigin.DebugString();
    }

    TInstant GetModificationTimestamp() const {
        return TInstant::Seconds(DocOrigin.GetModificationTimestamp());
    }

    const TString& GetBody() const {
        return DocOrigin.GetBody();
    }

    template <class T>
    bool GetFirstPropertyByName(const TString& propName, T* value) const {
        auto it = Properties.find(propName);
        if (it == Properties.end() || !it->second.size()) {
            return false;
        }
        if (value && !::TryFromString<T>(it->second[0], *value)) {
            return false;
        }
        return true;
    }

};
