#pragma once

#include "yt_command.h"
#include "config_files.h"

#include <saas/api/mr_client/processors/processors.h>
#include <saas/library/yt/common/yt_document.h>

#include <saas/rtyserver/config/common_indexers_config.h>
#include <saas/rtyserver/config/config.h>
#include <mapreduce/yt/interface/node.h>
#include <mapreduce/yt/interface/operation.h>

#include <util/generic/size_literals.h>

namespace NFusion {
    class TDocFetcherConfig;
}

class TSaasYTDocumentMapper
    : public NYT::IMapper<NYT::TTableReader<NYT::TNode>, NYT::TTableWriter<TYTDocument>>
{
public:
    struct TContext {
        TString ServiceName;
        TString SearchMapText;
        TString Processor;
        NSaas::TRowProcessorOptions ProcessorOptions;
        ui64 MaxDocumentsPerSegment;
        bool SaveDeletedDocuments;
        bool IsDelta = false;
        ui32 MinSegmentsCount;

        Y_SAVELOAD_DEFINE(ServiceName, SearchMapText, Processor, ProcessorOptions, MaxDocumentsPerSegment, SaveDeletedDocuments, IsDelta, MinSegmentsCount);
    };

public:
    TSaasYTDocumentMapper();
    TSaasYTDocumentMapper(TContext context, ui64 totalDocumentsCount, const TRtyConfigBundle& configBundle, bool addExtraTimestamp);
    ~TSaasYTDocumentMapper();

    void Start(TWriter* output) override;
    void Do(TReader* input, TWriter* output) override;

    void FillStreamSpecificFileds(NRTYServer::TMessage::TDocument& doc, const TReader* input) const;

    Y_SAVELOAD_JOB(Context, TotalDocumentsCount, ConfigBundle, AddExtraTimestamp);
private:
    THolder<NSearchMapParser::TSearchMap> SearchMap;
    const NSearchMapParser::TSearchCluster* Service;
    THolder<NSaas::IRowProcessor> RowProcessor;

    TContext Context;
    ui64 TotalDocumentsCount;

    TRtyConfigBundle ConfigBundle;
    bool AddExtraTimestamp = false;

    THolder<NFusion::TDocFetcherConfig> DocFetcherConfig;
    ui32 DefaultStreamId = 1;
    TString GrAttrToFillOnDelete = "";
    TSet<TString> FactorsToFillOnDelete;
};

class TProcessDocumentsCommand : public TYTCommand {
public:
    TProcessDocumentsCommand(TInputs inputs, TOutputs outputs, bool verbose, NSaas::TYTLaunchReport& report, TSaasYTDocumentMapper::TContext context,
        const TYTConfigFiles& configFiles, const TRtyConfigBundle& configBundle, bool addExtraTimestamp, ui32 ramGb, ui32 maxRowWeightMb, const NYT::TNode& acl)
        : TYTCommand(std::move(inputs), std::move(outputs), "TProcessDocumentsCommand", verbose, report, acl)
        , Context(std::move(context))
        , ConfigFiles(configFiles)
        , RamGb(ramGb)
        , MaxRowWeightMb(maxRowWeightMb)
        , ConfigBundle(configBundle)
        , AddExtraTimestamp(addExtraTimestamp)
    {
    }
    virtual ~TProcessDocumentsCommand() = default;

protected:
    virtual void DoPrepareSpec() override {
        Y_ENSURE(!Inputs.empty());
        for (const auto& input : Inputs) {
            Spec.AddInput<NYT::TNode>(input);
        }
        auto config = ConfigBundle.Parse();
        if(config->GetCommonIndexers().HtmlParserConfigFile)
            JobSpec.AddLocalFile(config->GetCommonIndexers().HtmlParserConfigFile);

        if(config->GetCommonIndexers().XmlParserConfigFile)
            JobSpec.AddLocalFile(config->GetCommonIndexers().XmlParserConfigFile);

        Spec.AddOutput<TYTDocument>(Outputs.at(0));
        if (MaxRowWeightMb > 0) {
            Opts.Spec(NYT::TNode()("job_io",
                NYT::TNode()("table_writer",
                    NYT::TNode()("max_row_weight", MaxRowWeightMb << 20))));
        }
        if (RamGb > 0) {
            JobSpec.MemoryLimit(RamGb * 1_GB);
        }
        ConfigFiles.FillSpecFiles(JobSpec);
        Spec.MapperSpec(JobSpec);
        Opts.InferOutputSchema(true);
    }

    virtual void DoRun(NYT::IClientBase* client) override {
        ui64 totalDocumentsCount = 0;
        for (const auto& attrs : InputAttrs) {
            totalDocumentsCount += attrs["row_count"].AsInt64();
        }
        client->Create(Outputs.at(0).Path_, NYT::ENodeType::NT_TABLE,
                        NYT::TCreateOptions().Recursive(true).Force(true)
                        .Attributes(NYT::TNode()("is_delta", Context.IsDelta)));
        Map(client, Spec, new TSaasYTDocumentMapper(Context, totalDocumentsCount, ConfigBundle, AddExtraTimestamp), Opts);
    }

private:
    NYT::TMapOperationSpec Spec;
    NYT::TUserJobSpec JobSpec;
    NYT::TOperationOptions Opts;
    const TSaasYTDocumentMapper::TContext Context;

    const TYTConfigFiles& ConfigFiles;
    ui32 RamGb;
    ui32 MaxRowWeightMb;

    const TRtyConfigBundle& ConfigBundle;
    bool AddExtraTimestamp = false;
};
