#include "parsed_entity.h"

#include <saas/rtyserver/config/config.h>
#include <saas/rtyserver/config/shards_config.h>
#include <saas/library/behaviour/behaviour.h>

#include <library/cpp/logger/global/global.h>

namespace {
    const TStringBuf QueryDelString = "query_del:";

    bool IsQueryDel(const NRTYServer::IComponentParserContext& context) {
        return context.Command == NRTYServer::TMessage::DELETE_DOCUMENT && context.Document.GetBody().find(QueryDelString) != TString::npos;
    }
}

void TBaseGeneratorEntityParser::ParseBody(TParsingContext& context) const {
    bool isQueryDel = IsQueryDel(context);
    if (!isQueryDel && context.Command == NRTYServer::TMessage::DELETE_DOCUMENT && !!context.Document.GetBody())
        throw yexception() << "Body without 'query_del:' for DELETE_DOCUMENT is not allowed";
    if (!GetBehaviour(context.Command).IsContentMessage && !!context.Document.GetBody())
        throw yexception() << "Body in non-content messages is not allowed";
    if (isQueryDel) {
        SetQueryDel(context.Result, context.Document.GetBody().data() + QueryDelString.length());
    }
}

void TBaseGeneratorEntityParser::ParseKeyPrefix(TParsingContext& context) const {
    bool isQueryDel = IsQueryDel(context);
    if (!isQueryDel && !GetBehaviour(context.Command).IsBroadcastMessage) {
        if ((context.Document.GetKeyPrefix() != 0) != context.Result.GetConfig().IsPrefixedIndex)
            throw yexception() << "KeyPrefix of document is set to " << context.Document.GetKeyPrefix() << " but IsPrefixedIndex == " << context.Result.GetConfig().IsPrefixedIndex;
        if ((ui64)context.Document.GetKeyPrefix() > Max<ui64>() - 2)
            throw yexception() << "KeyPrefix greater than Max<ui64>() - 2 (" << context.Document.GetKeyPrefix() << ")";
        if (!context.Result.GetConfig().GetShardsConfig().IsLocalShard(context.Result.GetShard()))
            throw yexception() << "This shard does not on this backend";
    }
}

void TBaseGeneratorEntityParser::ParseUpdate(TParsingContext& context) const {
    if (context.Command == NRTYServer::TMessage::DEPRECATED__UPDATE_DOCUMENT && context.Result.GetUpdateType() == NRTYServer::TMessage::SLOW) {
        RestoreIsNeeded(context.Result);
    }
}

void TBaseGeneratorEntityParser::Parse(TParsingContext& context) const {
    ParseBody(context);
    ParseKeyPrefix(context);
    ParseUpdate(context);
}
