#include "config.h"
#include "common_indexers_config.h"
#include "const.h"
#include "get_value.h"
#include "grouping_config.h"
#include "indexer_config.h"
#include "logger_config.h"
#include "merger_config.h"
#include "monitor_config.h"
#include "realm_config.h"
#include "repair_config.h"
#include "search_server_options.h"
#include "searcher_config.h"
#include "shards_config.h"
#include "sys_env.h"

#include <saas/rtyserver/logging/rty_access.h>
#include <saas/rtyserver/logging/rty_index.h>
#include <saas/util/logging/exception_process.h>
#include <saas/rtyserver/pruning_config/pruning_config.h>
#include <saas/library/daemon_base/daemon/messages.h>
#include <saas/rtyserver/factors/factors_config.h>
#include <saas/rtyserver/factors/factors_domain.h>
#include <saas/rtyserver/factors/rank_model.h>

#include <search/grouping/groupinfo.h>
#include <search/config/config.h>
#include <search/config/virthost.h>

#include <ysite/parser/xml/xml_yndx_transform.h>
#include <robot/library/oxygen/indexer/processor/protos/config.pb.h>
#include <kernel/groupattrs/docsattrswriter.h>

#include <library/cpp/digest/md5/md5.h>
#include <library/cpp/protobuf/protofile/protofile.h>
#include <library/cpp/html/zoneconf/ht_conf.h>
#include <library/cpp/html/face/parsface.h>
#include <library/cpp/json/json_reader.h>

#include <google/protobuf/text_format.h>

#include <util/folder/dirut.h>
#include <util/string/split.h>
#include <util/string/cast.h>
#include <util/string/vector.h>
#include <util/generic/algorithm.h>
#include <util/generic/size_literals.h>

THolder<NOxygen::TOxygenOptions> GetOxygenOptions(const TString& file, TConfigPreprocessor* preprocessor) {
    if (!file) {
        return nullptr;
    }
    Y_ENSURE(NFs::Exists(file), "Cannot find OxygenOptions file " << file);

    const TString& textConfig = preprocessor ? preprocessor->ReadAndProcess(file) : TUnbufferedFileInput(file).ReadAll();
    INFO_LOG << "OxygenOptions: " << Endl << textConfig << Endl;

    auto result = MakeHolder<NOxygen::TOxygenOptions>();
    if (!google::protobuf::TextFormat::ParseFromString(textConfig, result.Get())) {
        ythrow yexception() << "Cannot parse OxygenOptions from file " << file;
    }

    INFO_LOG << "OxygenOptionsParsed: " << Endl << result->Utf8DebugString() << Endl;
    return result;
}

TRTYServerConfig::TRTYServerConfig(const TServerConfigConstructorParams& params)
    : SysEnv(MakeHolder<NRTYServer::TSysEnv>())
    , SearcherConfig(MakeHolder<NRTYServer::TSearcherConfig>(*this))
    , BaseSearcherConfig(MakeHolder<NRTYServer::TSearchServerOptions>("BaseHttpListen", "BaseHttpReq", "BaseHttpFailReq"))
    , MetaSearcherConfig(MakeHolder<NRTYServer::TSearchServerOptions>("MetaHttpListen", "MetaHttpReq", "MetaHttpFailReq"))
    , RepairConfig(MakeHolder<NRTYServer::TRepairConfig>(*this))
    , MergerConfig(MakeHolder<NRTYServer::TMergerConfig>(*this))
    , LoggerConfig(MakeHolder<NRTYServer::TLoggerConfig>(*this))
    , MonitorConfig(MakeHolder<NRTYServer::TMonitorConfig>(*this))
    , CommonIndexers(MakeHolder<NRTYServer::TCommonIndexersConfig>(*this))
    , ComponentsConfig(*this, "ComponentsConfig")
    , ExternalLogicConfig(*this, "ExternalLogicConfig")
    , ModulesConfig(*this, "ModulesConfig")
    , StoragesConfig(*this, "StoragesConfig")
    , IndexDir(NFs::CurrentWorkingDirectory() + GetDirectorySeparator())
    , IndexGenerator(INDEX_COMPONENT_NAME)
    , IsPrefixedIndex(false)
    , AddSignalTags(false)
    , DDKManager(DDK_COMPONENT_NAME)
    , UrlToDocIdManager(URL2DOCID_COMPONENT_NAME)
    , VerificationPolicy(vpRelease)
    , IsSecondaryMetaServiceComponent(false)
    , DoStoreArchive(true)
    , UseExtendedProcessors(false)
    , Shards(MakeHolder<NRTYServer::TShardsConfig>())
    , IsReadOnly(false)
    , NoMorphology(false)
    , PreferedMorphologyLanguages("ru,en")
    , SearchersCountLimit(0)
    , IndexerMemoryConfig(MakeHolder<NRTYServer::TIndexerConfigMemory>(*CommonIndexers))
    , IndexerDiskConfig(MakeHolder<NRTYServer::TIndexerConfigDisk>(*CommonIndexers))
    , RealmListConfig(MakeHolder<NRTYServer::TRealmListConfig>(*this))
    , Pruning(TPruningConfig::Create(""))
    , ConfigPatcher(params.Preprocessor)
    , DaemonConfigHolder(params.Daemon)
    , DaemonConfig(*DaemonConfigHolder)
{
    CHECK_WITH_LOG(!!DaemonConfigHolder);
    CachePolicy = cpUnknown;
    ParseConfigsVersion();

    if (!!params.Text)
        InitFromString(params.Text);

    FileDigests.insert(std::make_pair("ServerConfig",
                                params.Path.empty() ? "" : MD5::File(params.Path)));
    FileDigests.insert(std::make_pair("BaseSearchConfig",
                                SearcherConfig->DefaultBaseSearchConfig.empty() ? "" : MD5::File(SearcherConfig->DefaultBaseSearchConfig)));
}

TRTYServerConfig::TRTYServerConfig(TDaemonConfigPtr daemonConfig)
    : SysEnv(MakeHolder<NRTYServer::TSysEnv>())
    , SearcherConfig(MakeHolder<NRTYServer::TSearcherConfig>(*this))
    , BaseSearcherConfig(MakeHolder<NRTYServer::TSearchServerOptions>("BaseHttpListen", "BaseHttpReq", "BaseHttpFailReq"))
    , MetaSearcherConfig(MakeHolder<NRTYServer::TSearchServerOptions>("MetaHttpListen", "MetaHttpReq", "MetaHttpFailReq"))
    , RepairConfig(MakeHolder<NRTYServer::TRepairConfig>(*this))
    , MergerConfig(MakeHolder<NRTYServer::TMergerConfig>(*this))
    , LoggerConfig(MakeHolder<NRTYServer::TLoggerConfig>(*this))
    , MonitorConfig(MakeHolder<NRTYServer::TMonitorConfig>(*this))
    , CommonIndexers(MakeHolder<NRTYServer::TCommonIndexersConfig>(*this))
    , ComponentsConfig(*this, "ComponentsConfig")
    , ExternalLogicConfig(*this, "ExternalLogicConfig")
    , ModulesConfig(*this, "ModulesConfig")
    , StoragesConfig(*this, "StoragesConfig")
    , IndexDir(NFs::CurrentWorkingDirectory() + GetDirectorySeparator())
    , IndexGenerator(INDEX_COMPONENT_NAME)
    , IsPrefixedIndex(false)
    , AddSignalTags(false)
    , DDKManager(DDK_COMPONENT_NAME)
    , UrlToDocIdManager(URL2DOCID_COMPONENT_NAME)
    , VerificationPolicy(vpRelease)
    , IsSecondaryMetaServiceComponent(false)
    , DoStoreArchive(true)
    , UseExtendedProcessors(false)
    , Shards(MakeHolder<NRTYServer::TShardsConfig>())
    , IsReadOnly(false)
    , NoMorphology(false)
    , PreferedMorphologyLanguages("ru,en")
    , SearchersCountLimit(0)
    , IndexerMemoryConfig(MakeHolder<NRTYServer::TIndexerConfigMemory>(*CommonIndexers))
    , IndexerDiskConfig(MakeHolder<NRTYServer::TIndexerConfigDisk>(*CommonIndexers))
    , RealmListConfig(MakeHolder<NRTYServer::TRealmListConfig>(*this))
    , Pruning(TPruningConfig::Create(""))
    , ConfigPatcher(nullptr)
    , DaemonConfigHolder(std::move(daemonConfig))
    , DaemonConfig(*DaemonConfigHolder)
{
    CHECK_WITH_LOG(!!DaemonConfigHolder);
    CachePolicy = cpUnknown;
    ParseConfigsVersion();
}

TRTYServerConfig::~TRTYServerConfig() = default;

void TRTYServerConfig::ParseConfigsVersion() {
    if (DaemonConfig.GetController().VersionsFileName.empty()) {
        return;
    }

    const TFsPath pathToVersionsFile = TFsPath(DaemonConfig.GetController().ConfigsRoot) / DaemonConfig.GetController().VersionsFileName;
    if (!pathToVersionsFile.Exists()) {
        INFO_LOG << "No configs version file" << Endl;
        return;
    }

    TFileInput fi(pathToVersionsFile);
    NJson::TJsonValue json = NJson::ReadJsonTree(&fi, true /* throwOnError */);

    for (const auto& [filename, version]: json.GetMapSafe()) {
        ConfigsVersions[filename] = version.GetIntegerSafe();
    }
}

void TRTYServerConfig::InitFromString(const TString& configText) {
    TAnyYandexConfig yandexConfig;
    if (!yandexConfig.ParseMemory(configText.data())) {
        TString errorMessage;
        yandexConfig.PrintErrors(errorMessage);
        Cerr << "Cannot parse config. Errors: " << errorMessage << Endl;
    }

    TYandexConfig::Section* serverSection = yandexConfig.GetFirstChild("Server");
    AssertCorrectConfig(serverSection, "There is no Server section in config");
    Init(serverSection->GetDirectives());
    TYandexConfig::TSectionsMap sections = serverSection->GetAllChildren();

    TYandexConfig::TSectionsMap::const_iterator iter = sections.find("Searcher");
    AssertCorrectConfig(iter != sections.end(), "There is no Searcher section in config");
    SearcherConfig->Init(yandexConfig, iter->second, ConfigPatcher ? ConfigPatcher->GetPreprocessor() : nullptr);

    iter = sections.find("BaseSearchersServer");
    AssertCorrectConfig(iter != sections.end(), "There is no BaseSearchersServer section in config");
    BaseSearcherConfig->Init(iter->second->GetDirectives());

    *MetaSearcherConfig = *BaseSearcherConfig;

    iter = sections.find("Repair");
    AssertCorrectConfig(iter != sections.end(), "There is no Repair section in config");
    RepairConfig->Init(iter->second->GetDirectives());

    iter = sections.find(NRTYServer::TResourceFetchConfig::SECTION_NAME);
    if (iter != sections.end()) {
        GlobalResourceFetchConfig.Init(*iter->second);
    }

    iter = sections.find("SystemEnvironment");
    if (iter != sections.end()) {
        SysEnv->Init(iter->second->GetAllChildren());

        if (SysEnv->Io["BatchWrite"] != TThrottle::TOptions::FromMaxPerSecond(30_MB, TDuration::Seconds(1))) {
            MergerConfig->WriteOption = SysEnv->Io["BatchWrite"];
        }
    }

    iter = sections.find("Merger");
    AssertCorrectConfig(iter != sections.end(), "There is no Merger section in config");
    MergerConfig->Init(*iter->second);

    iter = sections.find("Logger");
    if (iter != sections.end()) {
        LoggerConfig->Init(iter->second->GetDirectives());
    }

    iter = sections.find("Monitoring");
    AssertCorrectConfig(iter != sections.end(), "There is no Monitoring section in config");
    MonitorConfig->Init(iter->second->GetDirectives());

    iter = sections.find("Indexer");
    AssertCorrectConfig(iter != sections.end(), "There is no Indexer section in config");
    {
        TYandexConfig::TSectionsMap indexerSections = iter->second->GetAllChildren();
        TYandexConfig::TSectionsMap::const_iterator indIter = indexerSections.find("Common");
        AssertCorrectConfig(indIter != indexerSections.end(), "There is no Common section in indexer config");
        CommonIndexers->Init(indIter->second);
        indIter = indexerSections.find("Disk");
        AssertCorrectConfig(indIter != indexerSections.end(), "There is no Disk section in indexer config");
        IndexerDiskConfig->Init(indIter->second);
        indIter = indexerSections.find("Memory");
        AssertCorrectConfig(indIter != indexerSections.end(), "There is no Memory section in indexer config");
        IndexerMemoryConfig->Init(indIter->second);
        IndexerMemoryConfig->MaxDocuments = Max<ui32>(500, IndexerDiskConfig->MaxDocuments * IndexerMemoryConfig->MaxDocumentsReserveCapacityCoeff);
    }

    iter = sections.find("Realms");
    if (iter != sections.end()) {
        RealmListConfig->Init(iter->second);
    } else {
        RealmListConfig->InitDefaultConfig(sections.find("Indexer")->second, sections.find("Merger")->second);
    }

    ComponentsConfig.Init(*this, sections);
    ExternalLogicConfig.Init(*this, sections);

    TSet<TString> modules = ExternalLogicConfig.GetModules();

    for (auto&& i : modules) {
        if (ExternalLogicConfig.Get<IAbstractModuleConfig>(i)->ConfigurationExists()) {
            ExternalServiceLogic = IExternalServiceLogic::TFactory::Construct(i);
            CHECK_WITH_LOG(!!ExternalServiceLogic);
            break;
        }
    }

    ModulesConfig.Init(*this, sections);
    StoragesConfig.Init(*this, sections);
    NOTICE_LOG << "Config parsed: " << Endl;
    NOTICE_LOG << Endl << ToString() << Endl;
}

TSet<TString> TRTYServerConfig::GetModulesSet() const {
    return TSet<TString>(AdditionalModulesVector.cbegin(), AdditionalModulesVector.cend());
}

TVector<TString> TRTYServerConfig::GetModulesVector() const {
    return AdditionalModulesVector;
}

void TRTYServerConfig::Init(const TYandexConfig::Directives& directives) {
    GET_VALUE(IndexDir);
    GET_VALUE_DEF(IndexGenerator);
    GET_VALUE_DEF(DeadDocsClearIntervalSeconds);
    GET_VALUE_DEF(DeadIndexesClearIntervalSeconds);

    if (!IndexDir.empty()) {
        SlashFolderLocal(IndexDir);
        size_t pos;
        while ((pos = IndexDir.find('\\')) != TString::npos)
            IndexDir.replace(pos, 1, "/");
    }
    GET_VALUE(IsPrefixedIndex);
    GET_VALUE(AddSignalTags);
    GET_VALUE(DDKManager);
    if (!DDKManager) {
        DDKManager = DDK_COMPONENT_NAME;
    }
    GET_VALUE(UrlToDocIdManager);
    if (!UrlToDocIdManager) {
        UrlToDocIdManager = URL2DOCID_COMPONENT_NAME;
    }
    GET_VALUE(ShardMin);
    GET_VALUE(ShardMax);
    GET_VALUE(IsSecondaryMetaServiceComponent);
    GET_VALUE(DoStoreArchive);
    GET_VALUE(UseExtendedProcessors);
    GET_VALUE(IsReadOnly);

    Pruning.Reset(TPruningConfig::Create(directives.Value("PruneAttrSort", TString())));

    if (!TryFromString<>(directives.Value<TString>("VerificationPolicy", "Release"), VerificationPolicy)) {
        VerificationPolicy = TRTYServerConfig::vpRelease;
    }

    Shards->Init(directives);
    GET_VALUE(Components);
    TVector<TString> components;
    Split(Components, ", ;", components);
    ComponentsSet.clear();
    for (size_t i = 0; i < components.size(); i++)
        ComponentsSet.insert(components[i]);

    GET_VALUE(AdditionalModules);
    GET_VALUE(PreserveModulesOrder);
    AdditionalModulesVector = StringSplitter(AdditionalModules).SplitBySet(", ;").SkipEmpty();
    {
        auto sortedModules = AdditionalModulesVector;
        SortUnique(sortedModules);
        if (PreserveModulesOrder) {
            // ensure there're no duplicates
            AssertCorrectConfig(AdditionalModulesVector.size() == sortedModules.size(), "Duplicate AdditionalModules: %s", AdditionalModules.c_str());
        } else {
            // compatiblity with old behavior
            AdditionalModulesVector.swap(sortedModules);
        }
    }

    GET_VALUE(NoMorphology);
    GET_VALUE(MorphologyLanguages);
    GET_VALUE(PreferedMorphologyLanguages);
    GET_VALUE_DEF(SearchersCountLimit);
    if (!SearchersCountLimit) {
        bool AddSearcherAfterMergeOnly = false;
        GET_VALUE_DEF(AddSearcherAfterMergeOnly);
        if (AddSearcherAfterMergeOnly) {
            SearchersCountLimit = 1;
        }
    }

    TString watchdogOptionsFiles;
    NRTYServer::NImpl::GetValue(watchdogOptionsFiles, "WatchdogOptionsFile", directives);
    StringSplitter(watchdogOptionsFiles).Split(' ').AddTo(&WatchdogOptionsFiles);

    GET_VALUE(CanIgnoreIndexOriginOnRemoving);
}

TString TRTYServerConfig::ToString() const {
    TString s;
    TStringOutput so(s);
    so << DaemonConfig.ToString("DaemonConfig");
    so << "<Server>" << Endl;
    so << "IndexDir : " << IndexDir << Endl;
    so << "IndexGenerator : " << IndexGenerator << Endl;
    if (!!ExternalServiceLogic) {
        so << "ExternalServiceLogic : " << ExternalServiceLogic->GetName() << Endl;
    }
    so << "DeadDocsClearIntervalSeconds : " << DeadDocsClearIntervalSeconds << Endl;
    so << "DeadIndexesClearIntervalSeconds : " << DeadIndexesClearIntervalSeconds << Endl;
    so << "IsPrefixedIndex : " << IsPrefixedIndex << Endl;
    so << "AddSignalTags : " << AddSignalTags << Endl;
    so << "DDKManager : " << DDKManager << Endl;
    so << "UrlToDocIdManager : " << UrlToDocIdManager << Endl;
    so << "ShardMin : " << ShardMin << Endl;
    so << "ShardMax : " << ShardMax << Endl;
    so << "VerificationPolicy : " << ::ToString(VerificationPolicy) << Endl;
    so << "IsSecondaryMetaServiceComponent : " << IsSecondaryMetaServiceComponent << Endl;
    so << "DoStoreArchive : " << DoStoreArchive << Endl;
    so << "UseExtendedProcessors : " << UseExtendedProcessors << Endl;
    so << "PruneAttrSort : " << Pruning->ToString() << Endl;
    so << "ShardsNumber : " << Shards->ToString() << Endl;
    so << "NoMorphology : " << NoMorphology << Endl;
    so << "IsReadOnly : " << IsReadOnly << Endl;
    so << "MorphologyLanguages : " << MorphologyLanguages << Endl;
    so << "PreferedMorphologyLanguages : " << PreferedMorphologyLanguages << Endl;
    so << "SearchersCountLimit : " << SearchersCountLimit << Endl;
    so << "WatchdogOptionsFile : " << JoinVectorIntoString(WatchdogOptionsFiles, " ") << Endl;
    so << "CanIgnoreIndexOriginOnRemoving : " << CanIgnoreIndexOriginOnRemoving << Endl;
    so << "Components : " << Components << Endl;
    so << "AdditionalModules : " << AdditionalModules << Endl;
    so << "PreserveModulesOrder : " << PreserveModulesOrder << Endl;
    ComponentsConfig.ToString(&so);
    ExternalLogicConfig.ToString(&so);
    ModulesConfig.ToString(&so);
    StoragesConfig.ToString(&so);
    so << Endl << SearcherConfig->ToString() << Endl;
    so << BaseSearcherConfig->ToString("BaseSearchersServer");
    so << Endl << RepairConfig->ToString()  << Endl;
    GlobalResourceFetchConfig.ToString(so);
    so << Endl << MergerConfig->ToString()  << Endl;
    so << Endl << LoggerConfig->ToString()  << Endl;
    so << Endl << MonitorConfig->ToString()  << Endl;
    so << Endl << "<Indexer>" << Endl;
    CommonIndexers->ToString(so);
    IndexerDiskConfig->ToString(so);
    IndexerMemoryConfig->ToString(so);
    so << Endl << "</Indexer>" << Endl;
    so << Endl << RealmListConfig->ToString() << Endl;

    so << Endl << SysEnv->ToString() << Endl;
    so << "</Server>" << Endl;
    return s;
}

TRTYServerConfig::TRTYCachePolicy TRTYServerConfig::GetCachePolicy() const {
    if (CachePolicy == cpUnknown) {
        if (SearcherConfig->CacheOptions.UseCache) {
            if (SearcherConfig->ReArrangeOptions.find("CacheSupporter") != TString::npos) {
                CachePolicy = cpCacheLifeTimeModified;
            } else {
                CachePolicy = cpCacheLifeTime;
            }
        } else {
            CachePolicy = cpNoCache;
        }
    }
    return CachePolicy;

}

THolder<TRTYServerConfig> ParseRtyConfig(const TString& configText, const THashMap<TString, TString>& variables) {
    TMaybe<TConfigPatcher> patcher;
    if (!variables.empty()) {
        patcher.ConstructInPlace();
        patcher->SetVariables(variables);
    }
    TServerConfigConstructorParams params(configText.data(), "", patcher.Get());
    auto config = MakeHolder<TRTYServerConfig>(params);
    config->ConfigPatcher = nullptr;
    return config;
}

bool TRTYServerConfig::RealtimeEnabled() const {
    for (auto&& [realmName, realmConfig] : RealmListConfig->RealmsConfig) {
        if (realmConfig.Type == NRTYServer::ERealm::Realtime) {
            return true;
        }
    }
    return false;
}

const NRTYServer::TMergerConfig& TRTYServerConfig::GetMergerConfig() const {
    Y_VERIFY(!!MergerConfig);
    return *MergerConfig;
}

NRTYServer::TMergerConfig& TRTYServerConfig::GetMergerConfig() {
    Y_VERIFY(!!MergerConfig);
    return *MergerConfig;
}

const NRTYServer::TLoggerConfig& TRTYServerConfig::GetLoggerConfig() const {
    Y_VERIFY(!!LoggerConfig);
    return *LoggerConfig;
}

NRTYServer::TLoggerConfig& TRTYServerConfig::GetLoggerConfig() {
    Y_VERIFY(!!LoggerConfig);
    return *LoggerConfig;
}

const NRTYServer::TMonitorConfig& TRTYServerConfig::GetMonitorConfig() const {
    Y_VERIFY(!!MonitorConfig);
    return *MonitorConfig;
}

NRTYServer::TMonitorConfig& TRTYServerConfig::GetMonitorConfig() {
    Y_VERIFY(!!MonitorConfig);
    return *MonitorConfig;
}

const NRTYServer::TCommonIndexersConfig& TRTYServerConfig::GetCommonIndexers() const {
    Y_VERIFY(!!CommonIndexers);
    return *CommonIndexers;
}

NRTYServer::TCommonIndexersConfig& TRTYServerConfig::GetCommonIndexers() {
    Y_VERIFY(!!CommonIndexers);
    return *CommonIndexers;
}

const NRTYServer::TSysEnv& TRTYServerConfig::GetSysEnv() const {
    Y_VERIFY(!!SysEnv);
    return *SysEnv;
}

NRTYServer::TSysEnv& TRTYServerConfig::GetSysEnv() {
    Y_VERIFY(!!SysEnv);
    return *SysEnv;
}

const NRTYServer::TSearcherConfig& TRTYServerConfig::GetSearcherConfig() const {
    Y_VERIFY(!!SearcherConfig);
    return *SearcherConfig;
}

NRTYServer::TSearcherConfig& TRTYServerConfig::GetSearcherConfig() {
    Y_VERIFY(!!SearcherConfig);
    return *SearcherConfig;
}

const NRTYServer::TSearchServerOptions& TRTYServerConfig::GetBaseSearcherConfig() const {
    Y_VERIFY(!!BaseSearcherConfig);
    return *BaseSearcherConfig;
}

NRTYServer::TSearchServerOptions& TRTYServerConfig::GetBaseSearcherConfig() {
    Y_VERIFY(!!BaseSearcherConfig);
    return *BaseSearcherConfig;
}

const NRTYServer::TSearchServerOptions& TRTYServerConfig::GetMetaSearcherConfig() const {
    Y_VERIFY(!!MetaSearcherConfig);
    return *MetaSearcherConfig;
}

NRTYServer::TSearchServerOptions& TRTYServerConfig::GetMetaSearcherConfig() {
    Y_VERIFY(!!MetaSearcherConfig);
    return *MetaSearcherConfig;
}

const NRTYServer::TRepairConfig& TRTYServerConfig::GetRepairConfig() const {
    Y_VERIFY(!!RepairConfig);
    return *RepairConfig;
}

NRTYServer::TRepairConfig& TRTYServerConfig::GetRepairConfig() {
    Y_VERIFY(!!RepairConfig);
    return *RepairConfig;
}

const NRTYServer::TIndexerConfigMemory& TRTYServerConfig::GetIndexerMemoryConfig() const {
    Y_VERIFY(!!IndexerMemoryConfig);
    return *IndexerMemoryConfig;
}

NRTYServer::TIndexerConfigMemory& TRTYServerConfig::GetIndexerMemoryConfig() {
    Y_VERIFY(!!IndexerMemoryConfig);
    return *IndexerMemoryConfig;
}

const NRTYServer::TIndexerConfigDisk& TRTYServerConfig::GetIndexerDiskConfig() const {
    Y_VERIFY(!!IndexerDiskConfig);
    return *IndexerDiskConfig;
}

NRTYServer::TIndexerConfigDisk& TRTYServerConfig::GetIndexerDiskConfig() {
    Y_VERIFY(!!IndexerDiskConfig);
    return *IndexerDiskConfig;
}

const NRTYServer::TRealmListConfig& TRTYServerConfig::GetRealmListConfig() const {
    Y_VERIFY(!!RealmListConfig);
    return *RealmListConfig;
}

NRTYServer::TRealmListConfig& TRTYServerConfig::GetRealmListConfig() {
    Y_VERIFY(!!RealmListConfig);
    return *RealmListConfig;
}

const NRTYServer::TShardsConfig& TRTYServerConfig::GetShardsConfig() const {
    Y_VERIFY(!!Shards);
    return *Shards;
}

NRTYServer::TShardsConfig& TRTYServerConfig::GetShardsConfig() {
    Y_VERIFY(!!Shards);
    return *Shards;
}
