#pragma once

#include "signals.h"
#include "stream.h"

#include <saas/library/daemon_base/metrics/metrics.h>

struct TRTYServerConfig;

namespace NSaas {
    class TAction;
}

namespace NRTYServer {
    class TReply;
}

namespace NUtil {
    class TRepliesStorage;
}

namespace NFusion {
    using TActionPtr = TAtomicSharedPtr<NSaas::TAction>;

    struct TDocStreamConfig;
    class TBaseIndexingClient;
    struct TShardFilter;

    class TDocStream : public TBaseStream
    {
    protected:
        struct TDocStreamMetrics: public TCompositeMetric {
            TPart<TOrangeMetric> Acquired;
            TPart<TOrangeMetric> Exceptions;

            TDocStreamMetrics(const TString& name)
                : Acquired(this, GetMetricsPrefix() + JoinMetricName(name, "Acquired"))
                , Exceptions(this, GetMetricsPrefix() + JoinMetricName(name, "Exceptions"))
            {
            }
        };

    public:
        TDocStream(
            const TDocFetcherModule& owner, const TDocStreamConfig& config, const TRTYServerConfig& globalConfig, TLog& log);
        virtual ~TDocStream();

    protected: // TBaseStream
        void OnStreamStart() override;
        void OnStreamStop() override;
        void OnStreamBeforeStop() override;
        TTimeToSleep DoStreamIteration() final;
        virtual void OnDocStreamStart() = 0;
        virtual void OnDocStreamStop() = 0;

        virtual void ReportStatus(NJson::TJsonValue& status) = 0;

    protected:
        virtual TCommonDocStreamSignals* SignalsBase() const = 0;

    protected:
        virtual NFusion::TActionPtr GetDoc(TMap<TString, TString>& propsToLog, bool& skipSleepOnError) = 0;

        virtual void OnReply(const NRTYServer::TReply& reply, NFusion::TActionPtr action);
        virtual void OnAcquired(NFusion::TActionPtr action);

        virtual bool IsExhausted() const;
        virtual void OnExhausted(TTimeToSleep& timeToSleep);

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

    private: //IThreadLoop
        TTimeToSleep OnException() final;

    private:
        void IndexDoc(NFusion::TActionPtr doc);
        void TryToEnableSearch(const TInstant& now);
        NFusion::TActionPtr ProcessDoc(NFusion::TActionPtr action, const TMap<TString, TString>& propsToLog, const TInstant& now);

    protected:
        const TRTYServerConfig& RTYServerConfig;
        const TDocStreamConfig& DocStreamConfig;
        const THolder<NUtil::TRepliesStorage> Errors;
        THolder<TBaseIndexingClient> IndexingClient;
        TAutoGlobal<TDocStreamMetrics> BaseMetrics;
        THolder<TShardFilter> ShardFilter;

        TAtomic PessimizeEndTimestamp = 0;
        TInstant StartTimestamp = TInstant::Zero();
        TInstant LastDocumentTimestamp = TInstant::Zero();
        TInstant LastIncoming = TInstant::Zero();
        TInstant LastExhausted = TInstant::Zero();
    };
}
