#include "delta_subtask.h"

#include <robot/jupiter/library/rtdoc/file/docidmap_io.h>

#include <robot/jupiter/library/rtdoc/file/model/files.h>

using namespace NRtDoc;

namespace NFusion {
    NRtDoc::TBuilderTask MakeDeltaSubtask(const NRtDoc::IBuilderInputs& inputDirs, const TString& resMapFile) {
        Y_VERIFY(!resMapFile.empty());

        TVector<TDocIdMap> mergerMaps;     // method's input: local id -> final id
        TVector<TDocIdMap> deltaInputMaps; // method's output: local id -> sequential ids for shardmerge
        TDocIdMap deltaToFinalMap;         // method's output: sequential ids -> final ids
        NRtDoc::TBuilderTask deltaTask;    // method's output: IBuilderInputs for Jupiter processors

        size_t estimatedDocCount = 0;
        for (size_t i = 0; i < inputDirs.InputsSize(); ++i) {
            const auto& input = inputDirs.GetInputs(i);
            if (input.GetIsFinalIndex())
                continue;

            mergerMaps.emplace_back();
            TDocIdMapIo::Load(&mergerMaps.back(), input.GetSrcMapping());
            estimatedDocCount += mergerMaps.back().GetData()->size();
        }

        TDocIdMap::TData& outputMap = *deltaToFinalMap.MutableData();
        outputMap.resize(estimatedDocCount);

        size_t finalDocId = 0;
        size_t segmentNo = 0;
        for (size_t i = 0; i < inputDirs.InputsSize(); ++i) {
            const auto& input = inputDirs.GetInputs(i);
            if (input.GetIsFinalIndex())
                continue;

            const NRtDoc::TDocIdMap& item = mergerMaps[segmentNo++];

            Y_ENSURE(TDocIdMapIo::CheckMonotonic(&item));

            TDocIdMap jupiterInputForDelta;
            const TDocIdMap::TData& from = *item.GetData();
            TDocIdMap::TData& to = *jupiterInputForDelta.MutableData();

            to.resize(from.size());
            for (size_t i = 0; i < from.size(); ++i) {
                ui32 docid = from[i];
                if (docid != TDocIdMap::DeletedDocument()) {
                    outputMap[finalDocId] = from[i];
                    to[i] = finalDocId;
                    finalDocId++;
                } else {
                    to[i] = TDocIdMap::DeletedDocument();
                }
            }

            const TString deltaMapFile = input.GetSrcMapping() + TBuilderFiles::DeltaMapSuffix;
            TDocIdMapIo::Save(deltaMapFile, &jupiterInputForDelta);

            NRtDoc::TBuilderTask::TBuilderInput& newInput = *deltaTask.AddInputs();
            newInput.CopyFrom(input);
            newInput.SetSrcMapping(deltaMapFile);
        }

        outputMap.resize(finalDocId);
        TDocIdMapIo::Save(resMapFile, &deltaToFinalMap);

        const TString& portionsDir = inputDirs.GetDeltaDir();
        deltaTask.MutableOutput()->SetTempDir(portionsDir);

        return deltaTask;
    }
}
