#pragma once

#include <saas/rtyserver/common/path_name.h>
#include <saas/rtyserver/model/realm/realm.h>
#include "manager.h"

#include <saas/rtyserver/pruning_config/pruning_config.h>
#include <library/cpp/mediator/messenger.h>
#include <library/cpp/object_factory/object_factory.h>
#include <saas/util/types/interval.h>
#include <saas/util/messages_collector.h>


#include <kernel/search_daemon_iface/reqtypes.h>
#include <kernel/externalrelev/relev.h>

class IUrlIdInfo;
class TCommonSearch;
class IArchiveData;
class TGuardedDocument;
class TParsedDocument;
using TQueuedDocument = TAtomicSharedPtr<TGuardedDocument>;
class IKeysAndPositions;
class TSearchRequestData;
class TRTYSearchRequestContext;

namespace NGroupingAttrs {
    class TDocsAttrs;
}

namespace NSearchMapParser {
    using TShardIndex = ui32;
}

namespace NRTYServer {
    enum class EExecutionContext {
        ServerInitialization, Normalize, Merge, Sync, Close, Repair
    };

    class TIndexTimestamp;
    class TIndexPositions;
    class THistograms;

    class IIndexOwner {
    public:
        class TGuardIndexModification {
        public:
            explicit TGuardIndexModification(IIndexOwner* owner)
                : Owner(owner)
            {
                Owner->UnlinkIndexData();
            }
            ~TGuardIndexModification() {
                Owner->LinkIndexData();
            }
        private:
            IIndexOwner* Owner;
        };

    public:
        virtual ~IIndexOwner() = default;
        virtual ERealm GetRealm() const = 0;
        virtual TString GetRealmName() const = 0;
        virtual NGroupingAttrs::TDocsAttrs* GetGroupsAttrs() const = 0;
        virtual const IKeysAndPositions* GetYndex() const = 0;
        virtual const IUrlIdInfo* GetUrlIdInfo() const = 0;
        virtual bool DocumentIsRemoved(ui32 docid) const = 0;
    protected:
        virtual void LinkIndexData() = 0;
        virtual void UnlinkIndexData() = 0;
    };
} // namespace NRTYServer


class TComponentSearcher : public TThrRefBase {
public:
    using TPtr = TIntrusivePtr<TComponentSearcher>;

public:
    virtual bool ParseContext(const TRTYSearchRequestContext& context, TMessagesCollector& errors) = 0;

    virtual bool IsUsed(const TRTYSearchRequestContext&) const {
        return false;
    }

    virtual bool CanLookup() const {
        return false;
    }

    virtual TVector<ui32> Lookup() {
        // L0-stage filter (limit the L0 iterator to given docids)
        return {};
    }

    // may create an object that filters primary matches (post-TR filter)
    virtual TAtomicSharedPtr<IDocProcessor> CreateFilter() = 0;
};

class ISearchFilter {
public:
    virtual TComponentSearcher::TPtr CreateSpecialSearcher() const = 0;

    virtual ~ISearchFilter() = default;
};

class IIndexUpdater {
public:
    virtual ~IIndexUpdater() = default;
    virtual bool UpdateDoc(ui32 docId, TAtomicSharedPtr<TParsedDocument> doc) = 0;
    virtual bool RestoreDoc(ui32 docId, TAtomicSharedPtr<TParsedDocument>& doc) = 0;
    virtual void FinalizeUpdates() = 0;
};

class IRemapperUrlDocId {
protected:
    ui32 DoRemapUrls2DocIds(const TVector<TDocSearchInfo>& docInfos, TVector<ui32>& docIds) const;
    ui32 DoRemapUrls2DocIdCandidates(const TVector<TDocSearchInfo>& docInfos, TVector<TDocIdCandidate>& docIds) const;
public:
    virtual ~IRemapperUrlDocId() = default;
    virtual bool RemapUrl2DocId(const TDocSearchInfo& docInfo, ui32& docId) const = 0;
    virtual bool RemapUrl2DocIdCandidate(const TDocSearchInfo& docInfo, TDocIdCandidate& docId) const = 0;
    virtual ui32 RemapUrls2DocIds(const TVector<TDocSearchInfo>& docInfos, TVector<ui32>& docIds) const;
    virtual ui32 RemapUrls2DocIdCandidates(const TVector<TDocSearchInfo>& docInfos, TVector<TDocIdCandidate>& docIds) const;
    virtual ui32 GetDocumentsCount(bool keyWithDeleted = true) const = 0;
};

class IDDKManager;

class IGetterDDKManager {
public:
    virtual const IDDKManager& GetDDKManager() const = 0;
};

class IDDKManager : public IGetterDDKManager {
public:
    virtual ~IDDKManager() = default;

    const IDDKManager& GetDDKManager() const override {
        return *this;
    }

    virtual const IUrlIdInfo* GetUrlIdInfo() const = 0;

    virtual bool CheckDeadLine(ui32 docId, ui32 currentTimeMinutes) const = 0;
    virtual void MarkForDelete(ui32 docId, ui32 marker) const = 0;
    virtual void UpdateVersion(ui32 docId, ui32 version) const = 0;
    virtual void UpdateTimestamp(ui32 docId, ui32 timestamp) const = 0;
    virtual void UpdateVersionWithTimestamp(ui32 docId, ui32 version, ui32 timestamp) const = 0;

    virtual ui32 GetVersion(ui32 docId) const = 0;
    virtual ui32 GetTimeLiveStart(ui32 docId) const = 0;
    virtual ui32 GetDeadlineIfEnabled(ui32 docId) const = 0;
    virtual ui32 GetDeadline(ui32 docId) const = 0;
    virtual ui32 GetSourceWithNewVersion(ui32 docId) const = 0;
    virtual ui32 GetParsedEntitiesHash(ui32 docId) const = 0;
    virtual ui16 GetStreamId(ui32 docId) const = 0;
    virtual TDocSearchInfo::THash GetIdentifier(ui32 docId) const = 0;

    virtual bool IsDeadlineEnabled() const = 0;
    virtual bool IsReadOnly() const = 0;
    virtual ui64 GenerateUrlIdHash(const TDocSearchInfo& searchInfo) const = 0;
};

class IDocLenCalcer {
public:
    virtual ~IDocLenCalcer() = default;
    virtual ui32 GetDocLen(ui32 docid) const = 0;
};

class IIndexController: public IMessageProcessor, public IRemapperUrlDocId, public TNonCopyable {
public:
    enum EIndexType {
        FINAL = 0x0001,
        DISK = 0x0002,
        MEMORY = 0x0004,
        PREPARED = 0x0008,

        FINAL_MASK = FINAL | PREPARED
    };

    typedef TSharedPtr<IIndexController, TAtomicCounter, TNoAction> TPtr;

    class ICallback {
    public:
        virtual ~ICallback() = default;
        virtual void OnBeforeRemove(const TVector<ui32>& docIds) = 0;
        virtual void OnBeforeMark(const TVector<ui32>& docIds, ui32 mark) = 0;
    };

private:
    struct IIndexControllerLock {
        static inline void Acquire(IIndexController::TPtr* t) noexcept {
            CHECK_WITH_LOG(t && *t);
            (*t)->StartModification();
        }

        static inline void Release(IIndexController::TPtr* t) noexcept {
            CHECK_WITH_LOG(t && *t);
            (*t)->FinishModification();
        }
    };
    typedef TGuard<IIndexController::TPtr, IIndexControllerLock> TGuardIndexModification;

    TRWMutex MutexCallbacks;
    TVector<ICallback*> Callbacks;
    bool IsSearchSource_ = false;
    bool IsSearchable_ = true;

protected:
    TPtr Self;

protected:
    void RegisterIndex();
    void UnRegisterIndex();
    void RegisterSearcher();
    void UnregisterSearcher();

    virtual ui32 DoRemoveDocIdsUnsafe(const TVector<ui32>& docIds) = 0;
    virtual ui32 RemoveDocIdsUnsafe(const TVector<ui32>& docIds) final;

    virtual ui32 MarkDocIdsForDeleteUnsafe(const TVector<ui32>& docIds, ui32 marker) = 0;
    virtual ui32 RemoveOldDocuments(ui32 currentTimeMinutes);
    virtual void StartModification() {};
    virtual void FinishModification() {};

public:
    IIndexController()
        : Self(this)
    {
        CHECK_WITH_LOG(Self.RefCount() == 1);
    }
    ~IIndexController() override {
        CHECK_WITH_LOG(Self.RefCount() == 1);
    }

    virtual TString GetSearcherId() const {
        return Directory().BaseName();
    }

    void RegisterCallback(ICallback* callback) {
        TWriteGuard g(MutexCallbacks);
        Callbacks.push_back(callback);
    }

    bool UnregisterCallback(const ICallback* callback) {
        TWriteGuard g(MutexCallbacks);
        bool result = false;
        for (ui32 i = 0; i < Callbacks.size();) {
            if (Callbacks[i] == callback) {
                Callbacks.erase(Callbacks.begin() + i);
                result = true;
            } else {
                ++i;
            }
        }
        return result;
    }

    virtual bool IsSearching() const = 0;
    virtual ERequestType RequestType(const TCgiParameters& cgi) const = 0;
    virtual TCommonSearch* GetCommonSearch() const = 0;
    virtual const IDDKManager* GetDDKManager() const = 0;
    virtual const NRTYServer::IIndexComponentManager* GetManager(const TString& componentName) const = 0;
    virtual ERTYSearchResult SearchCustom(ICustomReportBuilder& reportBuilder, const TRTYSearchRequestContext& searchContext) const final;

    virtual void Prefetch() const {}
    virtual ui32 RemoveAll();
    virtual ui32 RemoveDocIds(const TVector<ui32>& docIds);
    virtual ui32 RemoveKps(ui64 kps) = 0;
    virtual ui32 MarkForDelete(const TVector<ui32>& docIds, ui32 marker);
    virtual bool IsRemoved(ui32 docId) const = 0;
    virtual IIndexUpdater* GetUpdater() = 0;
    virtual const TPathName& Directory() const = 0;
    virtual bool HasSearcher() const { VERIFY_WITH_LOG(false, "incorrect usage HasSearcher"); return false; }
    ui32 GetDocumentsCount(bool keyWithDeleted = true) const override = 0;
    virtual ui32 GetSearchableDocumentsCount() const = 0;
    virtual ui64 GetLockedMemorySize() const = 0;
    virtual ui64 GetFilesSize() const = 0;
    virtual ui32 GetShard() const = 0;
    virtual ui32 GetState() const = 0;
    virtual bool GetDocInfo(const ui32 /*docId*/, NJson::TJsonValue& /*result*/) const { return false; }
    virtual const NRTYServer::THistograms& GetHistograms() const = 0;
    virtual NRTYServer::TIndexTimestamp& GetTimestamp() const = 0;
    virtual NRTYServer::TIndexPositions& GetPositions() const = 0;
    virtual TInterval<double> GetPruneInterval() const = 0;
    virtual ui32 GetDocsCountInInterval(const TInterval<double>& interval) const = 0;
    virtual EIndexType GetType() const = 0;
    virtual NRTYServer::ERealm GetRealm() const = 0;
    virtual TString GetRealmName() const = 0;
    virtual bool UpdateDoc(ui32 docId, TAtomicSharedPtr<TParsedDocument> doc) = 0;
    virtual bool RestoreDoc(ui32 docId, TAtomicSharedPtr<TParsedDocument>& doc) = 0;

    virtual void OnSearchActivated() {
        CHECK_WITH_LOG(IsSearchable());
        IsSearchSource_ = true;
    }

    virtual ui32 GetSearchPriority() const {
        return 0;
    }

    virtual bool IsSearchSource() const final {
        return IsSearchSource_;
    }

    virtual bool IsSearchable() const final {
        return IsSearchable_;
    }

    virtual void SetSearchable(bool value) final {
        IsSearchable_ = value;
    }

    virtual bool DecodeIntoTempDocId(const TDocSearchInfo& /*from*/, TDocSearchInfo& /*to*/) const {
        return false;
    }

    virtual ui32 DecodeFromTempDocId(ui32 docId) const {
        return docId;
    }

    virtual void FillDocIds(TVector<ui32>& /*docIds*/) const {
        FAIL_LOG("Incorrect FillDocIds usage");
    }

    virtual const IKeysAndPositions* GetIndexData() const {
        return nullptr;
    }

    virtual TAutoPtr<TPruningConfig::ICalcer> CreatePruningCalcer() const {
        return nullptr;
    }

    TComponentSearcher::TPtr InitSpecialSearch(const TRTYSearchRequestContext& context, TMessagesCollector& errors) const;
};

class TMessageRegisterIndex: public IMessage {
private:
    IIndexController::TPtr IndexController;
public:
    explicit TMessageRegisterIndex(IIndexController::TPtr indexController)
        : IndexController(std::move(indexController)) {}

    inline IIndexController::TPtr GetIndexController() {
        return IndexController;
    }
};

class TMessageUnregisterIndex: public IMessage {
private:
    IIndexController::TPtr IndexController;
public:
    explicit TMessageUnregisterIndex(IIndexController::TPtr indexController)
        : IndexController(std::move(indexController)) {}

    inline IIndexController::TPtr GetIndexController() {
        return IndexController;
    }
};

class TMessageRegisterSearcher: public IMessage {
private:
    IIndexController::TPtr IndexController;
public:
    explicit TMessageRegisterSearcher(IIndexController::TPtr indexController)
        : IndexController(std::move(indexController)) {}

    inline IIndexController::TPtr GetIndexController() {
        return IndexController;
    }
};

class TMessageUnregisterSearcher: public IMessage {
private:
    IIndexController::TPtr IndexController;
public:
    explicit TMessageUnregisterSearcher(IIndexController::TPtr indexController)
    : IndexController(std::move(indexController)) {}

    inline IIndexController::TPtr GetIndexController() {
        return IndexController;
    }
};

class IIndexer: public IIndexController {
public:
    virtual void CloseIndex(const std::atomic<bool>* /*rigidStopSignal*/, NRTYServer::EExecutionContext) = 0;
    virtual bool Index(const TQueuedDocument& qDocument, int threadID) = 0;
    virtual bool UpdateTimestampsOnDelete(const TQueuedDocument& qDocument, int threadID) = 0;
    virtual bool IsFull() const = 0;
    virtual bool IsEmpty() const = 0;
};

class IUrlToDocIdManager {
public:
    IUrlToDocIdManager() = default;
    static const ui32 NotFound = Max<ui32>();
    virtual ui32 GetIdByDocInfo(const TDocSearchInfo& info) const = 0;
    virtual ui32 GetIdByHash(const NSaas::TDocHash& hash) const = 0;
    virtual TDocIdCandidate GetIdCandidateByDocInfo(const TDocSearchInfo& info) const = 0;
    virtual bool IsDocCandidateAlwaysVerified() const = 0;
    typedef NObjectFactory::TParametrizedObjectFactory<IUrlToDocIdManager, TString, const TString&> TRemapperFactory;
};
