#pragma once

#include <saas/rtyserver/final_index/final_index.h>
#include <saas/rtyserver/merger/library/merger.h>
#include <util/generic/vector.h>

struct TClusterInfo {
    ui32 SegmentShard;
    ui32 Id;

    TClusterInfo(ui32 segmentShard, ui32 id) {
        Id = id;
        SegmentShard = segmentShard;
    }

    TString ToString() const noexcept {
        return Sprintf("%010d_%010d", SegmentShard, Id);
    }

    TString FormatName(const TStringBuf& dirPrefix) const noexcept {
        return Sprintf("%.*s%010d_%010d", (i32)dirPrefix.size(), dirPrefix.data(), SegmentShard, Id);
    }
};

struct TDocPlaceInfo;

class TM2NDecoder : public TRTYMerger::IRTYMergerDocIdDecoder {
public:
    struct TOptions {
        ui32 SegmentSize;
        float SizeDeviation;
        ui32 MaxDeadlineDocs;
        bool Pruning;
        bool ReuseDocids = true;
        bool PushSignals = false;  // should be true when NoRT segments are merging
    };
public:
    TM2NDecoder(const TOptions& options);
    virtual ~TM2NDecoder();
    ui32 GetNewClustersCount() const;
    virtual TRTYMerger::TAddress Decode(ui32 clusterId, ui32 docId) const;
    virtual bool Check(ui32 clusterId, ui32 docId) const;
    virtual ui32 GetSizeOfCluster(ui32 clusterId) const;
    virtual ui32 GetSize() const;
    virtual bool IsValidClusterId(ui32 clusterId) const;
    virtual ui32 GetNewDocsCount(ui32 clusterId) const;
    virtual bool NewToOld(ui32 clusterId, ui32 docId, TRTYMerger::TAddress& addr) const;
    virtual void PatchDestMap(ui32 clusterId, const TVector<ui32>& remap);
    void AddInfo(const IDDKManager* source);
    void AddInfo(ui32 docId, i32 destinationId, const TDocPlaceInfo& docPlace, ui32 segmentShard);
    void Finalize();
    void Print(const char* prefix) const;
    TVector<TClusterInfo> GetClusters(ui32 destId) const;

private:
    class TBackDecoder;
    typedef TVector<TVector<TRTYMerger::TAddress> > TDirectDecoder;

    struct TDecoderStats {
        void AddSurplusDocs(ui32 count, TInstant maxDeadline);
        void Merge(const TDecoderStats&);
        void PushUnistatSignals() const;

    private:
        TInstant MaxRemovedDeadline;
        ui32 RemovedDeadlineDocs = 0;
    };

private:
    void InitDirectDecoder() const;

private:
    mutable THolder<TDirectDecoder> DirectDecoder;
    TMutex DirectDecoderMutex;
    THolder<TBackDecoder> BackDecoder;
    TVector<ui32> OldClusterSizes;
    ui32 OldDocsCount;
};
