#include "merger_action.h"

#include <saas/rtyserver/config/common_indexers_config.h>
#include <saas/rtyserver/config/grouping_config.h>
#include <saas/rtyserver/config/merger_config.h>
#include <search/base/yx_search.h>
#include <saas/rtyserver/index_storage/index_storage.h>
#include <saas/rtyserver/indexer_core/index_component_storage.h>
#include <saas/util/logging/exception_process.h>

#include <util/datetime/base.h>

TMergerAction::TMergerAction(const TRTYServerConfig& config, IMerger* merger, const TString& name)
    : Config(config)
    , Merger(merger)
    , Name(name)
{}

TMergerAction::~TMergerAction() {
    TempDir.ForceDelete();
}

bool TMergerAction::Do(const TVector<TString>& sources, const TVector<TString>& dests, const TVector<TString>& tmpfsDests, TRTYMerger::IRTYMergerDocIdDecoder* decoder, TRTYMerger::IRTYMergerDocIdInfo* info, IMergerCallback* callback, const std::atomic<bool>* rigidStopSignal, IMergerTask* task) {
    VERIFY_WITH_LOG(Merger, "Incorrect usage TMergerAction::Do method");
    VERIFY_WITH_LOG(!dests.empty(), "Incorrect usage TMergerAction::Do method. dests is empty");
    for (size_t i = 0; i < dests.size(); ++i) {
        const TString& dest = dests[i];
        TFsPath destPath(dest);
        destPath.MkDirs();
        TempDir = TFsPath(destPath.Parent()) / "merger" / destPath.Basename();
    }
    for (size_t i = 0; i < tmpfsDests.size(); i++) {
        TFsPath tmpfsDestPath(tmpfsDests[i]);
        tmpfsDestPath.MkDirs();
    }

    {
        TGuard<TMutex> g(Merger->GetResourcesMutex());
        TempDir.MkDirs();
    }
    TMaybeFail<NRTYServer::ERealm> realm;
    TMaybeFail<TString> realmName;
    for (auto&& source : sources) {
        const TIndexControllerPtr index = Merger->GetIndexStorage().GetIndexController(source);
        const NRTYServer::ERealm sourceRealm = index ? index->GetRealm() : NRTYServer::ERealm::Persistent;
        const TString sourceRealmName = index ? index->GetRealmName() : "Persistent";
        if (!realm) {
            realm = sourceRealm;
        }
        if (!realmName) {
            realmName = sourceRealmName;
        }
        VERIFY_WITH_LOG(*realm == sourceRealm && *realmName == sourceRealmName, "Cross-realm merger is forbidden");
    }
    NRTYServer::TMergeContext mergeContext(TRTYMerger::TContext(sources, dests, tmpfsDests, TempDir, decoder, info, callback), task, *realm, *realmName);
    mergeContext.Context.IndexaaVersion = Config.GetCommonIndexers().GroupingConfig->GetVersion();
    mergeContext.Identifier = Name;
    mergeContext.Merger = Merger;
    mergeContext.RigidStopSignal = rigidStopSignal;
    for (ui32 i = 0; i < sources.size(); ++i) {
        TIndexControllerPtr index = Merger->GetIndexStorage().GetIndexController(sources[i]);
        TFinalIndex* finalIndex = dynamic_cast<TFinalIndex*>(index.Get());
        if (!!finalIndex) {
            TBaseSearch* search = dynamic_cast<TBaseSearch*>(finalIndex->GetSearcher());
            TFsPath fs(sources[i] + "/index");
            if (search && search->IsSearching()) {
                mergeContext.Context.AdditionalData[fs.Fix().Parent().GetName()] = &search->GetArchiveManager();
            }
        }
    }
    mergeContext.Context.WriteOption = Config.GetMergerConfig().WriteOption;

    TRY
        return TIndexComponentsStorage::Instance().Merge(mergeContext);
    CATCH_AND_RETHROW(TString("while merger.MergeIndicies ") + Name)
}

bool TMergerAction::Do(const TVector<TString>& sources, const TString& dest, TRTYMerger::IRTYMergerDocIdDecoder* decoder, TRTYMerger::IRTYMergerDocIdInfo* info, IMergerCallback* callback, const std::atomic<bool>* rigidStopSignal, IMergerTask* task) {
    const TVector<TString> destinations = { dest };
    return Do(sources, destinations, TVector<TString>{}, decoder, info, callback, rigidStopSignal, task);
}
