#pragma once

#include <saas/indexerproxy/adapters/interface_adapter.h>

#include <util/generic/maybe.h>
#include <util/generic/set.h>

class TInternalDocument: public IAdapterContext {
protected:
    class TOptions: public IRequestOptions {
    private:
        const TInternalDocument& Parent;

    public:
        TOptions(const TInternalDocument& parent)
            : Parent(parent)
        {}
    public:
        virtual bool IsTrace() const override {
            return false;
        }
        virtual bool IsDeferredMessage() const override {
            return Parent.DeferredMessage;
        }
        virtual bool GetVerboseLogging() const override {
            return true;
        }
        virtual bool GetWaitReply() const override {
            return true;
        }
        virtual bool IsRealtime() const override {
            return true;
        }
        virtual bool HasTimeout() const override {
            return Parent.Timeout.Defined();
        }
        virtual ui64 GetSizeLimit() const override {
            return Max<ui64>();
        }
        virtual const TString& GetAuthCookie() const override {
            return Default<TString>();
        }
        virtual const TString& GetSource() const override {
            return Parent.Source;
        }
        virtual TDuration GetTimeout() const override {
            return *Parent.Timeout;
        }
        virtual bool GetBypassDistributor() const override {
            return false;
        }
        virtual bool QueueDisabled() const override {
            return Parent.DisableQueue;
        }
        virtual bool BackendAllowed(const TString& backend) const override {
            const auto& allowedBackends = Parent.AllowedBackends;
            if (allowedBackends.empty()) {
                return true;
            }

            return allowedBackends.contains(backend);
        }
        virtual bool GetHasRealtimeFlag() const override {
            return false;
        }
        virtual TDuration GetIndexSleep() const override {
            return TDuration::Zero();
        }
    };
private:
    const TString Service;
    const TString Adapter;
    const TBlob  Data;
    const TInstant ReceiveTime;
    TAtomicSharedPtr<TDispatchableDocument> Document;

protected:
    TOptions RequestOptions;
    TServerRequestData RD;
    TSet<TString> AllowedBackends;
    TMaybeFail<TDuration> Timeout;
    TString Source;
    TString Origin;
    TString RemoteAddr;
    TString QueryString;
    TString ScriptName;
    bool DisableQueue;
    bool DeferredMessage;

public:
    TInternalDocument(const TString& service, const TString& adapter, const TBlob data);

    virtual const TString& GetServiceName() const final {
        return Service;
    }
    virtual const TString& GetAdapterName() const final {
        return Adapter;
    }
    virtual const TServerRequestData& GetRD() const final {
        return RD;
    }
    virtual const IRequestOptions& GetRequestOptions() const override {
        return RequestOptions;
    }
    virtual const TBlob& GetPost() const final {
        return Data;
    }
    virtual TAtomicSharedPtr<TDispatchableDocument>& GetDocument() final {
        return Document;
    }
    virtual const TAtomicSharedPtr<TDispatchableDocument>& GetDocument() const final {
        return Document;
    }
    virtual TInstant GetReceiveTime() const final {
        return ReceiveTime;
    }
    virtual TString GetOrigin() const final {
        return Origin;
    }
    virtual TStringBuf GetRemoteAddr() const override {
        return RemoteAddr;
    }
    virtual TStringBuf GetQueryString() const override {
        return QueryString;
    }
    virtual TStringBuf GetScriptName() const override {
        return ScriptName;
    }
};
