#pragma once

#include <saas/rtyserver/common/common_rty.h>

#include <saas/rtyserver/indexer_core/guarded_document.h>
#include <saas/rtyserver/indexer_core/parsed_document.h>

#include <library/cpp/mediator/messenger.h>

class ISearchLocker;

struct TModifyResult {
public:
    enum EStatus {
        COMPLETED,
        REINDEX,
        OUTDATED,
        ERROR,
        NOTSET,
        DUPLICATED,
        REDUNDANT
    };
public:
    EStatus Status;
    ui32 Version;
    ui32 Timestamp;
    ui32 Count;

public:
    TModifyResult()
        : Status(NOTSET)
        , Version(0)
        , Timestamp(0)
        , Count(0)
    {}

    void UpdateStatus(EStatus status) {
        if (Status == NOTSET)
            Status = status;
    }
};

class IModifyAction {
public:
    virtual ui32 ModifyDocumentByDocId(IIndexController& index, const TVector<ui32>& docIds) = 0;
    virtual ~IModifyAction() {}
};

class TModifyActionVersionedDelete : public IModifyAction {
private:
    TQueuedDocument Document;
public:
    TModifyActionVersionedDelete(TQueuedDocument document);
    virtual ui32 ModifyDocumentByDocId(IIndexController& index, const TVector<ui32>& docIds);
};

class TModifyActionMarkAsDeleted: public IModifyAction {
private:
    const ui32 Marker;
public:
    TModifyActionMarkAsDeleted(const TString& indexDir);
    virtual ui32 ModifyDocumentByDocId(IIndexController& index, const TVector<ui32>& docIds);
};

class TModifyActionUpdate: public IModifyAction {
public:
    typedef THashMap<TDocSearchInfo::THash, TParsedDocument::TPtr> TDocsToIndex;

public:
    TModifyActionUpdate(TParsedDocument::TPtr document, const TString& deletionMarker);
    virtual ui32 ModifyDocumentByDocId(IIndexController& index, const TVector<ui32>& docIds);

    const TDocsToIndex& GetDocumentsToIndex() const {
        return DocumentsToIndex;
    }

    void MakeDiffAsDocument() {
        CHECK_WITH_LOG(DocumentsToIndex.size() == 0);
        DocumentsToIndex[DiffDocument->GetDocSearchInfo().GetHash()] = DiffDocument;
    }

private:
    TParsedDocument::TPtr DiffDocument;
    TDocsToIndex DocumentsToIndex;
    const TString DeletionMarker;
    const ui32 Marker;
};

class TMessageModifyDocument : public IMessage {
public:
    TMessageModifyDocument(TQueuedDocument document, IModifyAction& action);
    TQueuedDocument Document;
    IModifyAction& Action;
    TModifyResult Result;
};

class TDocumentModifier: public IMessageProcessor {
public:
    typedef TMap<TString, IIndexController::TPtr> TSegmentsMap;
    typedef TMap<TString, ui64> TDocsCountMap;

public:
    TDocumentModifier(const TRTYServerConfig& config, ISearchLocker* searchLocker);
    ~TDocumentModifier();

    // IMessageProcessor
    virtual bool Process(IMessage* message);
    virtual TString Name() const { return "TDocumentModifier"; }

    TModifyResult ModifyDocument(const TQueuedDocument& document, IModifyAction& action);

private:
    TSegmentsMap SegmentsMap;
    TDocsCountMap DocsCountPerSegment;
    ITransaction Transaction;
    const TRTYServerConfig& Config;
    ISearchLocker* SearchLocker;
    ui64 SearchableDocumentsCount = 0;

private:
    TModifyResult ModifyDocumentByUrl(const TParsedDocument& document, NRTYServer::TMessage::TMessageType messageType, IModifyAction& action);
    TModifyResult ModifyDocumentByQuery(const TParsedDocument& document, IModifyAction& action);
};

