#pragma once

#include <saas/util/guarded_object.h>
#include <saas/util/queue.h>

#include <library/cpp/logger/global/global.h>
#include <library/cpp/json/json_value.h>

#include <util/generic/hash.h>
#include <library/cpp/cgiparam/cgiparam.h>
#include <util/system/rwlock.h>
#include <util/string/cast.h>

class TAsyncTaskExecutor {
public:
    class TTask : public IObjectInQueue {
    public:
        enum TStatus { stsCreated, stsEnqueued, stsStarted, stsFinished, stsFailed, stsNotFound };
    private:
        TString Id;
        TStatus Status;

    protected:
        TRWMutex Mutex;
        NJson::TJsonValue Reply;
        virtual void DoSetStatus(const TString& /*message*/) {}

    public:
        typedef TAtomicSharedPtr<TTask> TPtr;
        TTask(const TString& id);
        virtual ~TTask() override {}
        virtual TString GetDescription() const;
        void FillInfo(NJson::TJsonValue& info) const;
        void SetStatus(TStatus status, const TString& message = TString());
        TGuardedPtr<NJson::TJsonValue, TRWMutex, TWriteGuard> GetReply() {
            return TGuardedPtr<NJson::TJsonValue, TRWMutex, TWriteGuard>(&Reply, Mutex);
        }
    };

    TAsyncTaskExecutor(const TString& name = {});

    virtual TTask::TPtr DoProcessRequest(const TCgiParameters& cgi, NJson::TJsonValue& result);
    virtual ui32 GetThreadsCountForTasks() const = 0;

    bool ProcessRequest(const TCgiParameters& cgi, NJson::TJsonValue& result);
    void AddTask(TTask::TPtr task, NJson::TJsonValue& result);
    const TTask::TPtr GetTask(const TString& taskId) const;
    virtual void Start();
    virtual void Stop();
    virtual ~TAsyncTaskExecutor() {}

protected:
    typedef THashMap<TString, typename TTask::TPtr> TTasksMap;
    TTasksMap TasksMap;
    TRTYMtpQueue Tasks;
    TRWMutex RWMutex;
};

template <>
TAsyncTaskExecutor::TTask::TStatus FromStringImpl<TAsyncTaskExecutor::TTask::TStatus, char>(const char* data, size_t len);
