#pragma once

#include <library/cpp/balloc/setup/alloc.h>
#include <saas/library/daemon_base/config/watchdog_opts.h>
#include <saas/library/daemon_base/daemon/info.h>
#include <saas/library/daemon_base/daemon/controller.h>
#include <saas/rtyserver/indexer_server/indexer_server.h>
#include <saas/rtyserver/merger/index_merger.h>
#include <saas/rtyserver/modifier/document_modifier.h>
#include <saas/rtyserver/repairer/repair.h>
#include <saas/rtyserver/search/neh/server.h>
#include <saas/rtyserver/search/http/server.h>

class IWatchDog;
class TStartupJournal;
class TRTYServerDiagState;

class TRTYServer: public IMessageProcessor, public IServer {
public:
    using TConfig = TRTYServerConfig;
    using TInfoCollector = TMessageCollectServerInfo;

    enum TRigidStopLevel {
        rslNO = 0,
        rslLOW = 1,
        rslHIGH = 2
    };

public:
    const TRTYServerConfig& Config;
    THolder<TSearchEnginesManager> SearchEnginesManager;
    TDocumentModifier DocumentModifier;
    TDefaultKeyPrefix DefaultKeyPrefix;
    THolder<TBaseSearchServer> BaseSearchServer;

private:
    THolder<TMainSearchServer> SearchServer;
    THolder<TMetaSearchNehServer> MetaSearchServer;

    TInstant Start;
    TIndexStorage::TPtr IndexStorage;
    TIndexMerger IndexMerger;
    THolder<TIndexRepair> IndexRepair;
    THolder<IWatchDog> SearchPortChecker;
    THolder<IWatchDog> DeadDocsCleaner;
    THolder<IWatchDog> DeadIndexesCleaner;
    TWatchdogOptionsHandlePtr WatchdogOptions;
    TVector<THolder<TIndexerServer>> IndexerServers;
    bool RunExecuted;

private:
    void InitializeBalloc() const;

    void StopIndexers(TString typeIndexer, bool rigidStop);
    void StartIndexers();

    void ProcessStartupJournal() const;
    void StartSearchWatchDog();
    void StopSearchWatchDog();

public:
    TRTYServer(const TRTYServerConfig& config);
    ~TRTYServer();

    const TIndexStorage& GetIndexStorage() const {
        return *IndexStorage;
    }
    const IMerger& GetMerger() const {
        return IndexMerger;
    };

    virtual bool Process(IMessage* message);
    virtual TString Name() const {
        return "RTYServer";
    }
    bool IsRepairing() const {
        return !!IndexRepair && IndexRepair->IsRepairing();
    }
    bool IsStarted() const {
        return Status != tsStopped;
    }
    bool CanSetConfig() const {
        return IsStarted();
    }
    void CreateModulesContext(IDaemonModule::TStartContext& ctx) {
        ctx = IDaemonModule::TStartContext(WatchdogOptions.Get());
    }

    void StartSearchServer();
    void StopSearchServer();
    bool IsSearchServerRunning();

    void Run();
    void Stop(ui32 rigidStopLevel = rslNO, const TCgiParameters* cgiParams = nullptr);
    void WaitEmptyQueues() const;

private:
    TInstant SearchBanTimestamp;
    TThreadStatus Status;
    TString StatusProgress;
    TMutex StopMutex;
    THolder<TStartupJournal> StartupJournal;
    THolder<TRTYServerDiagState> DiagState;
};
