#pragma once

#include "indexer_proxy_specific.h"
#include "request_opts.h"

#include <saas/indexerproxy/adapters/interface_adapter.h>
#include <saas/indexerproxy/configs/config.h>
#include <saas/indexerproxy/dispatching/dispatcher.h>
#include <saas/library/authorization/auth.h>
#include <saas/library/daemon_base/config/watchdog_opts.h>
#include <saas/library/daemon_base/metrics/servicemetrics.h>
#include <library/cpp/http/misc/httpcodes.h>
#include <saas/util/destroyer.h>
#include <saas/util/queue.h>
#include <library/cpp/string_utils/quote/quote.h>

class TFinishExecutor: public TOptionalRTYMtpQueue {
public:
    TFinishExecutor(bool smart)
        : TOptionalRTYMtpQueue(smart, "SendTaskExecFin")
    {}

    void Finish(IObjectInQueue* object) {
        CHECK_WITH_LOG(AddAndOwn(THolder(object)));
    }
};

class TTaskExecutor: public TOptionalRTYMtpQueue {
private:
    const TProxyConfig& Config;
    TProxyWatchdogSubsciber& WatchdogSubscriber;

    TDispatcher& Dispatcher;
    NSaas::TAuthorization& Authorizer;
    ISenderTask::TDestroyer& Destroyer;
    TStaticServiceMetrics& Metrics;
    TFinishExecutor FinishExecutor;
    TLog Dumper;
public:

    TTaskExecutor(const TProxyConfig& config, TProxyWatchdogSubsciber& wdSub, TStaticServiceMetrics& metrics,
                  ISenderTask::TDestroyer& destroyer, TDispatcher& dispatcher, NSaas::TAuthorization& authorizer)
        : TOptionalRTYMtpQueue(config.GetUsesSmartQueues(), "SendTaskExec")
        , Config(config)
        , WatchdogSubscriber(wdSub)
        , Dispatcher(dispatcher)
        , Authorizer(authorizer)
        , Destroyer(destroyer)
        , Metrics(metrics)
        , FinishExecutor(config.GetUsesSmartQueues())
        , Dumper(config.GetDumpFile())
    {
    }

    virtual void Start(size_t maxThreadCount, size_t queueSizeLimit = 0) override {
        FinishExecutor.Start(maxThreadCount, queueSizeLimit);
        TOptionalRTYMtpQueue::Start(maxThreadCount, queueSizeLimit);
    }

    const TStaticServiceMetrics& GetMetrics() const {
        return Metrics;
    }

    void StopFinishExecutor() {
        FinishExecutor.Stop();
    }

    void AddContext(IAdapterContext* context);

    TDispatcher& GetDispatcher() {
        return Dispatcher;
    }

    bool HasDumper() const {
        return !Dumper.IsNullLog();
    }

    TLog& GetDumper() {
        return Dumper;
    }

    const TProxyConfig& GetConfig() const {
        return Config;
    }

    void* CreateThreadSpecificResource () override {
        return new TAdaptersManager(Config, WatchdogSubscriber, Dispatcher, Authorizer);
    }

    void DestroyThreadSpecificResource(void* arg) override {
        delete (TAdaptersManager*)(arg);
    }
};
