#pragma once

#include "manager.h"
#include <saas/rtyserver/indexer_core/abstract_model.h>
#include <saas/rtyserver/indexer_core/parsed_document.h>
#include <saas/rtyserver/indexer_core/index_component_storage.h>

#include <util/generic/string.h>
#include <util/generic/vector.h>
#include <util/system/rwlock.h>
#include <util/system/guard.h>

class TBaseGeneratorBuilder;

namespace NJson {
    class TJsonValue;
}

class TRTYIndexManagersStorage: public NRTYServer::IIndexManagersStorage {
private:
    typedef std::pair<TString, THolder<NRTYServer::IIndexComponentManager> > TManagerRec;
    typedef TVector<TManagerRec> TManagerList;

    mutable TRWMutex ReadWriteMutex;
    TManagerList Managers;
    const TRTYServerConfig& RTYConfig;
protected:
    const NRTYServer::IIndexComponentManager* GetManagerImplNoLock(const TString& name) const;
public:
    TRTYIndexManagersStorage(const TRTYServerConfig& rtyConfig)
        : RTYConfig(rtyConfig)
    {
    }
    void KillManagers();
    void InitInteractions();

public: // NRTYServer::IIndexManagersStorage
    const NRTYServer::IIndexComponentManager* GetManagerImpl(const TString& name) const override;
public: // NRTYServer::IIndexManagersStorage
    bool HasIndexManager() const override;
    const TBaseGeneratorManager* GetIndexManager() const override;
    const IDDKManager* GetDDKManager() const override;
    const IUrlToDocIdManager* GetUrlToDocIdManager() const;
    THolder<NRTYServer::IDocSearchInfoIterator> GetDocSearchInfoIterator() const override;
    void RegisterManager(const TString& name, THolder<NRTYServer::IIndexComponentManager> manager) override;
    void CheckDocumentsNumber(ui32 docsCount) const override;
    bool UpdateDoc(ui32 docId, const TParsedDocument::TPtr doc) override;
    ui32 RemoveDocids(const TVector<ui32>& docids) override;
    ui32 MarkDocIdsForDeleteUnsafe(const TVector<ui32>& docids, ui32 marker) override;
    void Prefetch() const override;

public: // NRTYServer::IIndexComponentManager
    bool DoOpen() override;
    bool DoClose() override;
    ui32 GetDocumentsCount() const override;
    void InitInteractions(const NRTYServer::IIndexManagersStorage& /*storage*/) override;
    bool GetDocInfo(const ui32 docId, NJson::TJsonValue& result) const override;
};

class TRTYIndexBuildersStorage: public NRTYServer::IIndexBuildersStorage, public NRTYServer::IIndexComponentBuilder {
private:
    typedef std::pair<TString, THolder<NRTYServer::IIndexComponentBuilder> > TBuilderRec;
    typedef TVector<TBuilderRec> TBuilderList;

    mutable TRWMutex ReadWriteMutex;
    const TRTYServerConfig& RTYConfig;
    bool IsRunning;
    TBuilderList Builders;
    TRTYIndexManagersStorage Managers;
    TVector<TString> ManagersForOpen;
private:
    NRTYServer::IIndexComponentBuilder* GetBuilderImplNoLock(const TString& name) const;

public:
    typedef TAtomicSharedPtr<TRTYIndexBuildersStorage> TPtr;

public:
    TRTYIndexBuildersStorage(const TRTYServerConfig& rtyConfig, const TIndexComponentsStorage::TComponentsOrdered& managersOrder)
        : NRTYServer::IIndexComponentBuilder("BUILDERS_STORAGE")
        , RTYConfig(rtyConfig)
        , IsRunning(false)
        , Managers(RTYConfig)
    {
        for (const auto& i: managersOrder) {
            ManagersForOpen.push_back(i->GetName());
        }
    }

    ~TRTYIndexBuildersStorage() {
        KillBuilders();
    }

    virtual bool IsClosed() const { return !IsRunning; }
    void KillBuilders();

    NRTYServer::IIndexManagersStorage* GetManagers() { return dynamic_cast<NRTYServer::IIndexManagersStorage *>(&Managers); }
    const NRTYServer::IIndexManagersStorage* GetManagers() const { return &Managers; }
    bool Start(bool initManagersInteractions);


protected: // NRTYServer::IIndexBuildersStorage
    NRTYServer::IIndexComponentBuilder* GetBuilderImpl(const TString& name) const override;
public: // NRTYServer::IIndexBuildersStorage
    void RegisterBuilder(const TString& name, THolder<NRTYServer::IIndexComponentBuilder> builder) override;

    bool HasIndexBuilder() const;
    TBaseGeneratorBuilder* GetIndexBuilder() const;

public: // NRTYServer::IIndexComponentBuilder
    NRTYServer::IIndexComponentManager* GetManager() override;
    void Index(int threadID, const TParsedDocument& document, const ui32 docId) override;
    bool DoClose(const NRTYServer::TBuilderCloseContext& context) override;
    void DoDiscard() override;
    bool Start() override {
        return Start(/* initManagersInteractions = */ false);
    }
    bool Stop() override;
    void InitInteractions(const NRTYServer::IIndexBuildersStorage& /*storage*/) override;
};
