#pragma once

#include "doc_extractor.h"
#include "m2n_decoder.h"

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

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

#include <library/cpp/digest/md5/md5.h>

#include <util/string/vector.h>

#include <atomic>

class TDetachTask: public IMergerTask {
public:

    typedef TInterval<NSearchMapParser::TShardIndex> TShardInterval;
    typedef THashMap<ui32, TVector<TString> > TSegmentsForCopy;

    struct TContext {
        const TRTYServerConfig& Config;
        TVector<TShardInterval> ShardIntervals;
        NSaas::TShardsDispatcher::TContext Sharding;
        TString DetachDirectory;
        TString YtPath;
        TString YtProxy;
        bool ClearPrevious = false;
        ui32 DestSegmentSize;
        float DestSegmentSizeDeviation;
        const std::atomic<bool>* StopFlag;
        bool Share = true;
        bool UploadToYt = false;
        TContext(const TRTYServerConfig& config)
            : Config(config)
            , Sharding(NSaas::UrlHash)
        {
        }
    };

private:
    bool DocumentIsAccepted(const TDocPlaceInfo& doc, ui32& interval) const;
    bool ShortProcessing(const TDocPlaceMap& shardsMap, TIndexControllerPtr index);
    THolder<TRTYMerger::IRTYMergerDocIdDecoder> Decoder;
    TVector<TString> DestSegments;
    TVector<TString> SourceSegments;
    TSegmentsForCopy SegmentsForCopy;
    bool IsCorrect;
    TInstant Time;
    const TContext& Context;
protected:
    virtual TString DoBuildTempDest(IIndexStorage& storage, const TString& segment) const override;
    virtual TString DoBuildFullDest(IIndexStorage& storage, const TString& segment) const override;
    virtual void DoBuildDecoder(IIndexStorage& storage) override;

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

    virtual void DoOnBeforeMainStage() override { }

    virtual void DoOnFinished(const std::atomic<bool>* /*rigidStop*/) override {
        NOTICE_LOG << "Detach task finished for " << JoinStrings(GetFullDestinations(), " ") << Endl;
    }
    virtual void DoOnFailed() override {}
public:

    virtual void MoveFromTemp(ui32 destIndex, IIndexStorage& /*storage*/, const std::atomic<bool>* /*rigidStop*/) override {
        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);
    }

    TVector<TClusterInfo> GetClusters(ui32 destId) const;

    TRTYMerger::IRTYMergerDocIdDecoder* GetDecoder() override {
        return Decoder.Get();
    }

    TRTYMerger::IRTYMergerDocIdInfo* GetInfo() override {
        return nullptr;
    }

    TDetachTask(const TContext& context)
        : IMergerTask("", nullptr, context.Config.GetRealmListConfig().GetMainRealmConfig().ConfigName)
        , IsCorrect(false)
        , Time(Now())
        , Context(context)
    {}

    virtual ~TDetachTask() {
    }

    int GetShardNumber() const override { FAIL_LOG("NOT APPLICABLE METHOD"); }

    const TVector<TString>& GetSourceSegments() const override;
    const TVector<TString>& GetDestSegments() const override;
    const TSegmentsForCopy& GetSegmentsForCopy() const;
    bool NeedToMerge() const;

    TString GetName() const override {
        return MD5::Calc(GetDescription());
    };

    virtual TString GetDescription() const {
        TString shardsInfo;
        for (ui32 i = 0; i < Context.ShardIntervals.size(); ++i) {
            shardsInfo += Context.ShardIntervals[i].ToString() + ".";
        }
        return shardsInfo + Context.Sharding.ToString() + "-" + Time.ToString();
    };

    bool NeedWriteSourceIndexes() const override {
        return false;
    }

    bool GetIsPortions() const override {
        return false;
    }

    virtual NRTYServer::EExecutionContext GetExecutionContext() const override {
        return NRTYServer::EExecutionContext::Sync;
    }
};
