#include "merge_move_task.h"

#include <saas/rtyserver/config/config.h>
#include <saas/rtyserver/config/merger_config.h>
#include <saas/rtyserver/config/realm_config.h>

#include <saas/rtyserver/merger/doc_extractor.h>

TMergeMoveTask::TMergeMoveTask(const TRTYServerConfig& config, IIndexStorage& storage, TVector<TString> sourceSegments, TString workingDirectory, TString destSegment)
    : IMergerTask("", nullptr, config.GetRealmListConfig().GetMainRealmConfig().ConfigName)
    , Config(config)
    , Storage(storage)
    , WorkingDirectory(std::move(workingDirectory))
    , SourceSegments(std::move(sourceSegments))
    , DestSegments( { std::move(destSegment) } )
{
}

const TVector<TString>& TMergeMoveTask::GetSourceSegments() const {
    return SourceSegments;
}

const TVector<TString>& TMergeMoveTask::GetDestSegments() const {
    return DestSegments;
}

void TMergeMoveTask::DoBuildDecoder(IIndexStorage& storage) {
    TM2NDecoder::TOptions options;
    options.SegmentSize = Config.GetMergerConfig().MaxDocumentsToMerge;
    options.SizeDeviation = 0.5f;
    options.MaxDeadlineDocs = Config.GetMergerConfig().MaxDeadlineDocs;
    options.Pruning = false;

    // effectively we always build M-to-1 decoder
    Decoder.Reset(new TM2NDecoder(options));
    for (auto& segmentName : SourceSegments) {
        TIndexControllerPtr index = storage.GetIndexController(segmentName);
        CHECK_WITH_LOG(index);
        Decoder->AddInfo(index->GetDDKManager());
        const ui32 maxDocId = index->GetDocumentsCount(true);
        for (ui32 docId = 0; docId < maxDocId; ++docId) {
            if (!index->IsRemoved(docId)) {
                TDocPlaceInfo info;
                Decoder->AddInfo(docId, 0, info, 0);
            }
        }
    }
    Decoder->Finalize();
    CHECK_WITH_LOG(Decoder->GetNewClustersCount() == 1);
}

void TMergeMoveTask::MoveFromTemp(ui32 destIndex, IIndexStorage& /*storage*/, const std::atomic<bool>* /*rigidStop*/) {
    CHECK_WITH_LOG(GetTempDestinations().size() == GetFullDestinations().size());
    CHECK_WITH_LOG(GetTempDestinations().size() > destIndex);
    TFsPath path(GetTempDestinations()[destIndex]);
    TFsPath pathTo(GetFullDestinations()[destIndex]);
    pathTo.MkDirs();
    path.RenameTo(pathTo);
}

TString TMergeMoveTask::DoBuildTempDest(IIndexStorage& /*storage*/, const TString& segment) const {
    return GetTempDir() + "/" + segment;
}

TString TMergeMoveTask::DoBuildFullDest(IIndexStorage& /*storage*/, const TString& segment) const {
    return WorkingDirectory + "/" + segment;
}

bool TMergeMoveTask::DoOnStart(const std::atomic<bool>* /*rigidStop*/) {
    return true;
}

void TMergeMoveTask::DoOnBeforeMainStage() {
}

void TMergeMoveTask::DoOnFinished(const std::atomic<bool>* /*rigidStop*/) {
    Storage.RemoveIndexes(SourceSegments, false);
    TFsPath(GetTempDir()).ForceDelete();
}

void TMergeMoveTask::DoOnFailed() {
}

TString TMergeMoveTask::GetTempDir() const {
    return WorkingDirectory + "/" + GetName();
}
