#pragma once

#include "final_index_processor.h"

#include <saas/rtyserver/common/common_messages.h>
#include <saas/rtyserver/modifier/deferred_index_updater.h>
#include <saas/rtyserver/search/external_search/rty_index_data.h>
#include <saas/library/histogram/histogram.h>
#include <search/config/virthost.h>

class TSearchRequestData;

class TFinalIndex : public IIndexWithComponents, public TFinalIndexProcessor {
public:
    static TFinalIndex* Create(const TString& indexDir, const TRTYServerConfig& config, const TString& originDir, TVector<ui32>* decoder, NRTYServer::EExecutionContext execCtx);
    ~TFinalIndex();
    virtual void Prefetch() const override;

    virtual void OnSearchActivated() override;
    virtual bool UpdateDoc(ui32 docId, const TParsedDocument::TPtr doc) override;
    virtual bool RestoreDoc(ui32 docId, TParsedDocument::TPtr& doc) override;

    virtual bool IsSearching() const override;

    virtual ERequestType RequestType(const TCgiParameters& cgi) const override;
    virtual TCommonSearch* GetCommonSearch() const override;

    virtual ui32 GetSearchPriority() const override {
        return IsMergedIndex ? 10 : 0;
    }

    virtual void StartModification() override {
        MutexFrqWrite.Acquire();
    }
    virtual void FinishModification() override {
        MutexFrqWrite.Release();
    }

    virtual ui32 GetDocumentsCount(bool keyWithDeleted = true) const override {
        return GetDocumentsCountImpl(keyWithDeleted);
    }

    virtual ui32 GetSearchableDocumentsCount() const override {
        return GetSearchableDocumentsCountImpl();
    }

    virtual ui64 GetFilesSize() const override; //IIndexController
    virtual ui64 GetLockedMemorySize() const override; //IIndexController

    virtual ui32 GetShard() const override {
        return Shard;
    }

    virtual ui32 GetDocsCountInInterval(const TInterval<double>& interval) const override;
    virtual ui32 GetState() const override;
    virtual TInterval<double> GetPruneInterval() const override;

    void Start();
    inline bool GetIsStarted() const {
        return IsStarted;
    }

    inline void DropSearcher() {
        DEBUG_LOG << "DropSearcher: " << Directory().BaseName() << " ..." << Endl;
        if (IsStarted) {
            UnregisterSearcher();
            IsHasSearcher = false;
        }
        DEBUG_LOG << "DropSearcher: " << Directory().BaseName() << " ...OK" << Endl;
    }

    //IIndexController
    virtual bool HasSearcher() const override {
        return IsHasSearcher;
    }

    virtual ui32 DecodeFromTempDocId(ui32 docIdTemp) const override;
    virtual ui32 DoRemoveDocIdsUnsafe(const TVector<ui32>& docIds) override;
    virtual ui32 MarkDocIdsForDeleteUnsafe(const TVector<ui32>& docIds, ui32 marker) override;
    virtual void FillDocIds(TVector<ui32>& docIds) const override;

    virtual const IDDKManager* GetDDKManager() const override {
        return DDKManager;
    }

    virtual NRTYServer::TIndexTimestamp& GetTimestamp() const override {
        return Timestamp;
    }

    virtual NRTYServer::TIndexPositions& GetPositions() const override {
        return Positions;
    }

    virtual const NRTYServer::THistograms& GetHistograms() const override {
        return Histograms;
    }

    virtual EIndexType GetType() const override;
    virtual NRTYServer::ERealm GetRealm() const override;
    virtual TString GetRealmName() const override;

    virtual TCommonSearch* GetSearcher();
    virtual bool IsRemoved(const ui32 docid) const override;
    virtual const TPathName& Directory() const override;
    virtual IIndexUpdater* GetUpdater() override;
    void SetDeferredUpdatesStorage(TDeferredUpdatesStorage::TPtr storage);
    virtual bool RemapUrl2DocId(const TDocSearchInfo& docInfo, ui32& docId) const override;
    virtual bool RemapUrl2DocIdCandidate(const TDocSearchInfo& docInfo, TDocIdCandidate& docId) const override;

    virtual const NRTYServer::IIndexComponentManager* GetManager(const TString& componentName) const override {
        return Managers.GetManager<NRTYServer::IIndexComponentManager>(componentName);
    }

    bool RemapIdentifier2DocId(const TDocSearchInfo::THash& identifier, ui32& docId) const;
    virtual bool GetDocInfo(const ui32 docId, NJson::TJsonValue& result) const override;
    virtual ui32 RemoveKps(ui64 kps) override;

    //IMessageProcessor
    virtual bool Process(IMessage* message) override;
    virtual TString Name() const override;

    //IIndexOwner
    virtual const IKeysAndPositions* GetYndex() const override;
    virtual NGroupingAttrs::TDocsAttrs* GetGroupsAttrs() const override;

    virtual const NRTYServer::IIndexManagersStorage& GetManagers() const override {
        return Managers;
    }

    virtual NRTYServer::IIndexOwner& GetIndexOwner() override {
        return *this;
    }

    virtual const IKeysAndPositions* GetIndexData() const override;
    virtual TAutoPtr<TPruningConfig::ICalcer> CreatePruningCalcer() const override;

    void StartSearcher() {
        CHECK_WITH_LOG(!IsHasSearcher);
        IsHasSearcher = true;
        RegisterSearcher();
    }

    const TString& GetOriginDir() {
        return OriginDir;
    }

protected:
    TFinalIndex(const TString& indexDir, const TRTYServerConfig& config, const TString& originDir, TVector<ui32>* decoder, NRTYServer::EExecutionContext execCtx);

    virtual void LinkIndexData() override;
    virtual void UnlinkIndexData() override;
    virtual void Initialize() override;

    ui32 FixDocumentsCount(const ui32 deadlineCount);
    void LoadHistograms();

private:
    void PrefetchFiles(const TIndexFileEntries& files) const;
    void PrefetchFilesGroup(const TStringBuf name, const NRTYServer::IIndexFilesGroup& component, TIndexFileEntries& lockIndexFiles, TIndexFileEntries& prefetchIndexFiles) const;
    void LockFiles(const TIndexFileEntries& files) const;
    void UnlinkSelfIndexData();

private:
    TRWMutex MutexDocIdsByNextVersionSourceHash;
    THashMap<ui32, TVector<ui32>> DocIdsByNextVersionSourceHash;
    TMutex MutexFrqWrite;
    THolder<TRTYIndexData> IndexData;
    mutable NRTYServer::TIndexTimestamp Timestamp;
    mutable NRTYServer::TIndexPositions Positions;
    NRTYServer::THistograms Histograms;
    TString OriginDir;
    bool IsHasSearcher;
    bool IsStarted;
    TVector<ui32> Decoder;
    ui32 NextDeadline;
    TDeferredIndexUpdater Updater;
    TMaybe<TFilesSizeInfo> FileSizes;
    bool IsMergedIndex = false;
    mutable TVector<TString> LockedIndexFiles;
    mutable TAtomic LockedIndexFilesSize = 0;
};

typedef TAtomicSharedPtr<TFinalIndex> TFinalIndexPtr;
