#pragma once

#include "abstract/merger.h"
#include "abstract/update.h"

#include <saas/rtyserver/components/generator/builder.h>

#include <saas/rtyserver/indexer_core/abstract_model.h>

#include <robot/library/oxygen/indexer/idspace/groupattrmap.h>
#include <robot/library/oxygen/indexer/processor/bundle/interface.h>
#include <robot/library/oxygen/indexer/processor/protos/config.pb.h>
#include <robot/library/oxygen/indexer/processor/processor/processor.h>

#include <kernel/tarc/dirconf/dirconf.h>

namespace NRTYServer {
    class TProcessorProfiler;
}

class TFreshMixer;

class TTuplesListsAndFilters;
class TRTYOxyConfig;

struct TProcessorsBuilderContext: public NOxygen::TCreateProcessorsContext {
    bool ForMerger = false;
    bool ForUpdate = false;
    const NOxygen::TOxygenOptions& OxygenConfig;
    const TTuplesListsAndFilters* TuplesListsAndFilters = nullptr;
    THolder<TOxyMergerConfig> MergerOptions;

    NOxygen::TProcessorPtr ProcessorsCollection;
    TVector<NOxygen::TProcessorPtr> Processors;
    TVector<NOxygen::TProcessorPtr> HostProcessors;
    TVector<IOxyMerger::TPtr> MergersWithUpdaters;
    TVector<IOxyMerger::TPtr> MergersWithoutUpdaters;
    TVector<IOxyUpdater::TPtr> Updaters;

public:
    TProcessorsBuilderContext(const NOxygen::TOxygenOptions& oxygenConfig);

    TProcessorsBuilderContext& SetDir(const TString& dir) {
        OutputDirectory = dir;
        TemporaryDirectory = dir;
        return *this;
    }

    TProcessorsBuilderContext& SetTuples(const TTuplesListsAndFilters* tuples) {
        TuplesListsAndFilters = tuples;
        return *this;
    }

    TProcessorsBuilderContext& SetForMerger(bool value = true) {
        ForMerger = value;
        return *this;
    }

    TProcessorsBuilderContext& SetForUpdate(bool value = true) {
        ForUpdate = value;
        return *this;
    }

    TProcessorsBuilderContext& InitAttrs(NOxygen::TGroupAttrMap& map) {
        GroupAttrMap = &map;
        return *this;
    }
};

class TOXYIndexBuilder: public TBaseIndexBuilder {
private:
    const TFsPath Directory;
    const NOxygen::TOxygenOptions OxygenOptions;
    const TRTYOxyConfig& ComponentConfig;
    const bool PruneOnly;
    const bool ForMerge;
    const TTuplesListsAndFilters& TuplesListsAndFilters;
    const TBaseGeneratorBuilder* FA;
    const NRTYServer::TProcessorProfiler* ProcessorProfiler;

    NOxygen::TGroupAttrMap AttrMap;
    NOxygen::TProcessorPtr CollectProcess;
    TIntrusivePtr<NOxygen::IPruningProcessor> PruningProcess;
    mutable THolder<NOxygen::TDocIdMap> MapRemap;
    NOxygen::TCallbackBasePtr CompositeCallback;

private:
    static void BuildUpdater(TProcessorsBuilderContext& context, const NOxygen::TProcessorPtr& processor);
    static void InitMergerOptions(TOxyMergerConfig& config, const TRTYOxyConfig& componentConfig, const NOxygen::TOxygenOptions& oxyOptions);

    void CancelDocument(const TParsedDocument& document, const ui32 docId, const TString& message);
    void ReportStats();

public:
    TOXYIndexBuilder(
        const TFsPath directory,
        const NOxygen::TOxygenOptions& oxygenOptions,
        const TRTYServerConfig& globalConfig,
        bool pruneOnly,
        bool forMerge,
        const TTuplesListsAndFilters& tuplesListsAndFilters,
        const TString& componentName
    );

    void Index(int threadID, const TParsedDocument& document, const ui32 docId) override;
    bool IndexEmpty(int threadID, const ui32 docId); // used when there is no processors
    bool DoClose(const NRTYServer::TBuilderCloseContext& context) override;
    bool Start() override;

    bool Stop() override {
        return true;
    }

    static bool BuildProcessors(TProcessorsBuilderContext& context);
    static NOxygen::IPruningProcessorPtr BuildPruningProcessor(NOxygen::TProcessorPtr slave, const TProcessorsBuilderContext& context);

    ui32 GetResortMapForMerge(const IIndexController::TPtr index, TVector<ui32>& result) const override;
    void InitInteractions(const NRTYServer::IIndexBuildersStorage& /*storage*/) override;
};
