#pragma once

#include <saas/library/daemon_base/unistat_signals/signals.h>

#include <library/cpp/mediator/messenger.h>
#include <library/cpp/threading/atomic/bool.h>

#include <util/generic/ptr.h>

namespace NSaas {
    class TAction;
}

namespace NRTYServer {
    class TReply;
}

namespace NFusion {
    using TActionPtr = TAtomicSharedPtr<NSaas::TAction>;
    struct TDocStreamConfig;
    class TDocFetcherConfig;

    class TCommonDocStreamSignals
        : public TSaasUnistatSignals
        , public IMessageProcessor
    {
    public:
        TCommonDocStreamSignals(const TDocStreamConfig& config);
        virtual ~TCommonDocStreamSignals();

        virtual void ProcessExhausted();
        virtual void ProcessExpired(TActionPtr action);
        virtual void ProcessIncoming(TActionPtr action);
        virtual void ProcessIndexed(TActionPtr action, const NRTYServer::TReply &reply);
        void ProcessAttrs(TActionPtr action);
        void SetReceiveTimestamp(ui64 timestamp);

        void Init(TUnistat &t) const override;

    protected:
        void DrillHolesReply(TUnistat &t) const;
        void ProcessReply(TActionPtr action, const NRTYServer::TReply& reply);
        void ProcessAttr(const TString &distrAttr);

        void Build();
        void InitAttrs(TUnistat &t) const;

        // NMessenger::IMessageProcessor
        virtual TString Name() const override;
        virtual bool Process(IMessage* message) override;

    protected:
        const TString SignalSuffix;
        TSet<TString> DistributionAttributes; //attributes to track
        TAtomic LastReceiveTimestamp;
        NAtomic::TBool IsExhausted;

    private:
        virtual void ProcessTimestamps(TActionPtr action);
    };

    class TSyncSignals : public TSaasUnistatSignals {
    public:
        TSyncSignals();
        void UpdateSyncStatus(bool syncStatus);

        void Init(TUnistat& t) const override;
    };

    class TDocFetcherSignals
        : public TSaasUnistatSignals
        , public IMessageProcessor
    {
    private:
        struct TSignalInfo {
            TString Name;
            EAggregationType AggregationType;
            TSignalInfo(const TString &name, EAggregationType aggregationType)
                : Name(name)
                , AggregationType(aggregationType)
            {}
        };

    public:
        TDocFetcherSignals(const TDocFetcherConfig &FetcherConfig);
        ~TDocFetcherSignals();
        // NMessenger::IMessageProcessor
        virtual TString Name() const override;
        virtual bool Process(IMessage* message) override;

    public:
        void Init(TUnistat& t) const override;

    private:
        TVector<TString> DocStreamSignalSuffixes;
        TVector<TSignalInfo> DocSignalsToAggregate;
    };

    class TPersQueueStreamSignals: public TCommonDocStreamSignals {
        static constexpr TStringBuf ConsumerNotLockedSignalName = "-consumer-not-locked";
    public:
        TPersQueueStreamSignals(const TDocStreamConfig& config);

        void ConsumerLocked(bool isLocked);
    };

    template<typename TSignalsType = TCommonDocStreamSignals>
    class SignalsHolder {
    public:
        template<typename... Args>
        SignalsHolder(Args&&... args) {
            Signal = MakeHolder<TSignalsType>(std::forward<Args>(args)...);
        }

        TSignalsType* Signals() const {
            return Signal.Get();
        }

    private:
        THolder<TSignalsType> Signal;
    };
}
