#include "indexers_thread.h"

#include <saas/library/behaviour/behaviour.h>
#include <saas/rtyserver/common/common_messages.h>
#include <saas/rtyserver/logging/rty_index.h>

#include <saas/rtyserver/config/config.h>
#include <saas/rtyserver/config/indexer_config.h>
#include <saas/rtyserver/config/common_indexers_config.h>

bool TIndexersThread::IsRealtime(TQueuedDocument& document) const {
    return Config.GetIndexerMemoryConfig().Enabled && document->GetRuntimeKey();
}

TModifyResult TIndexersThread::ProcessDelete(TQueuedDocument& document, const TString& indexName) {
    const TRTYMessageBehaviour& behaviour = GetBehaviour(document->GetCommand());

    THolder<IModifyAction> action;
    if (behaviour.IsPureDeletion || IsRealtime(document)) {
        action = MakeHolder<TModifyActionVersionedDelete>(document);
    } else {
        action = MakeHolder<TModifyActionMarkAsDeleted>(indexName);
    }
    const TModifyResult& result = ModifyDocument(document, action.Get());
    QueueDocumentLog(ServiceName, document->GetDocument(), indexName, ("(REMOVED " + ToString(result.Count) + ")&(ADD DOCUMENT START)"));
    return result;
}

TModifyResult TIndexersThread::ProcessUpdate(TQueuedDocument& document, const TString& indexName, bool mayFast) {
    TModifyResult result;
    try {
        TParsedDocument::TPtr parsedDocument = document->GetDocumentPtr();
        TModifyActionUpdate updateAction(parsedDocument, IsRealtime(document) ? Default<TString>() : indexName);
        result = ModifyDocument(document, &updateAction);

        const TModifyActionUpdate::TDocsToIndex& docs = updateAction.GetDocumentsToIndex();
        const bool fastUpdate = parsedDocument->GetUpdateType() == NRTYServer::TMessage::FAST;
        const bool unmodified = docs.empty() && !result.Count;
        if (Config.GetCommonIndexers().StoreUpdateData && unmodified && !fastUpdate) {
            updateAction.MakeDiffAsDocument();
            result.Count++;
        }

        if (docs.empty()) {
            SendGlobalMessage<TMessageFastUpdateInvoked>(parsedDocument->GetDocSearchInfo(), result.Count);
            if (mayFast) {
                if (result.Count) {
                    document->SetStatus(NRTYServer::TReply::OK, "");
                    result.UpdateStatus(TModifyResult::COMPLETED);
                } else {
                    document->SetStatus(NRTYServer::TReply::INCORRECT_UPDATE, "No documents were updated");
                    result.UpdateStatus(TModifyResult::ERROR);
                }
            }
        } else if (docs.size() > 1) {
            document->SetStatus(NRTYServer::TReply::INCORRECT_UPDATE, "Too many documents to update (" + ToString(docs.size())+ ")");
            result.UpdateStatus(TModifyResult::ERROR);
        } else {
            CHECK_EQ_WITH_LOG(parsedDocument->GetDocSearchInfo().GetUrl(), docs.begin()->second->GetDocSearchInfo().GetUrl());
            document->SetDocument(docs.begin()->second);
            document->MutableCommand() = NRTYServer::TMessage::ADD_DOCUMENT;

            SendGlobalMessage<TMessageSlowUpdateInvoked>(parsedDocument->GetDocSearchInfo());
            result.UpdateStatus(TModifyResult::REINDEX);
            return result;
        }
    } catch (const yexception& e) {
        document->SetStatus(NRTYServer::TReply::INCORRECT_UPDATE, e.what());
    }
    QueueDocumentLog(ServiceName, document->GetDocument(), indexName, ("(UPDATED " + ToString(result.Count) + ")"));
    result.UpdateStatus(TModifyResult::COMPLETED); // if status is NOTSET, set COMPLETED
    return result;
}

TModifyResult TIndexersThread::ModifyDocument(const TQueuedDocument& document, IModifyAction* action) {
    const TModifyResult& modified = Deleter.ModifyDocument(document, *action);
    DEBUG_LOG << "Url " << document->GetDocument().GetDocSearchInfo().GetUrl()
        << (modified.Count ? "" : " wasn't found and can't be")
        << " modified"
        << (Config.GetCommonIndexers().StoreUpdateData ? " but stored" : "")
        << Endl;
    return modified;
}
