#include "server.h"
#include "executor.h"

#include <saas/deploy_manager/unistat_signals/signals.h>
#include <saas/deploy_manager/scripts/common/scripts_helper.h>
#include <saas/deploy_manager/storage/abstract.h>
#include <saas/deploy_manager/meta/cluster.h>
#include <saas/deploy_manager/scripts/common/deploy/deploy_builder.h>
#include <saas/deploy_manager/scripts/cluster/script_controller.h>
#include <saas/deploy_manager/modules/cache/cache_module.h>
#include <saas/deploy_manager/modules/services20/module.h>
#include <saas/deploy_manager/modules/nanny/nanny.h>
#include <saas/library/daemon_base/actions_engine/controller_client.h>
#include <saas/library/daemon_base/protos/status.pb.h>
#include <saas/util/external/dc.h>
#include <saas/util/cluster/cluster.h>
#include <saas/util/logging/exception_process.h>
#include <saas/util/network/http_request.h>
#include <saas/util/queue.h>

#include <library/cpp/json/json_reader.h>
#include <util/random/random.h>
#include <util/string/vector.h>
#include <util/system/event.h>
#include <util/system/mem_info.h>


class TTaskCleaner: public IObjectInQueue {
private:
    NRTYDeploy::ICommonData* CommonData;
    TManualEvent& Active;
    const TDeployManagerConfig& Config;
public:
    TTaskCleaner(NRTYDeploy::ICommonData* commonData, TManualEvent& active, const TDeployManagerConfig& config)
        : CommonData(commonData)
        , Active(active)
        , Config(config)
    {
    }

    void Process(void*) final {
        NRTYDeploy::TClusterTask::RemoveExpiredTasks(CommonData, TDuration::Seconds(Config.GetStorageOptions().ClusterTaskLifetimeSec), Active);
    }
};

THttpDeployManager::THttpDeployManager(const TDeployManagerConfig& config)
    : Config(config)
    , ScriptsServiceQueue(TThreadPool::TParams().SetBlocking(true).SetCatching(true))
{
    Storage.Reset(NRTYDeploy::IVersionedStorage::Create(config.GetStorageOptions()));
    NannyModule.Reset(new TNannyModule(config.GetNanny()));
    SDModule.Reset(new TSDModule(config.GetServiceDiscoveryOptions(), *this));
    Resources.Reset(new NRTYDeploy::TResourcesManager(*this));
    ControllersChecker.Reset(new NRTYDeploy::TControllersChecker(*Storage, config.GetChecker()));
    Queue.Reset(new NRTYDeploy::TZooQueue(config.GetStorageOptions()));
    Server.Reset(new THttpServer(this, config.GetHttpOptionsConfig()));
    RequestWizardModule.Reset(new TRequestWizardModule(config));
    Services20Module.Reset(new TServices20Module(config));
    JugglerModule.Reset(new TJugglerModule(config.GetAlertsConfig()));
    GolovanModule.Reset(new TGolovanModule(config.GetAlertsConfig()));
    WatchDog.Reset(new NRTYDeployServer::TWatchDog(*this));
    CacheModule.Reset(new NRTYDeploy::TCacheModule());

    TSaasDmUnistatSignals::BuildSignals();
}

THttpDeployManager::~THttpDeployManager()
{}

void THttpDeployManager::Stop(ui32 /*rigidStopLevel*/, const TCgiParameters* /*cgiParams*/) {
    INFO_LOG << "Server stopping..." << Endl;
    INFO_LOG << "Stopping Watchdog..." << Endl;
    WatchDog->Stop();
    INFO_LOG << "Stopping Watchdog...OK" << Endl;
    ActiveRegular.Signal();
    INFO_LOG << "Stopping ExecutorRegular..." << Endl;
    ExecutorRegular.Stop();
    INFO_LOG << "Stopping ExecutorRegular...OK" << Endl;
    Active.Signal();
    INFO_LOG << "Stopping Executor..." << Endl;
    Executor.Stop();
    INFO_LOG << "Stopping Executor...OK" << Endl;
    INFO_LOG << "Stopping Server..." << Endl;
    Server->Stop();
    INFO_LOG << "Stopping Server...OK" << Endl;
    INFO_LOG << "Server stopping...OK" << Endl;
    ScriptsServiceQueue.Stop();
    INFO_LOG << "Scripts service queue stopping...OK" << Endl;
}

void THttpDeployManager::Run() {
    Active.Reset();
    ActiveRegular.Reset();

    ScriptsServiceQueue.Start(Config.GetServiceQueueThreads());
    CHECK_WITH_LOG(Server->Start());
    Executor.Start(Config.GetTasksExecutorThreads() + 1);
    for (ui32 i = 0; i < Config.GetTasksExecutorThreads(); ++i) {
        Executor.SafeAdd(new NRTYDeployServer::TExecutor(this, Active, Config));
    }

    if (Config.GetStorageOptions().ClusterTaskLifetimeSec != 0) {
        Executor.SafeAddAndOwn(THolder(new TTaskCleaner(this, Active, Config)));
    }

    ExecutorRegular.Start(2);
    for (ui32 i = 0; i < 2; ++i) {
        ExecutorRegular.SafeAddAndOwn(THolder(new NRTYDeployServer::TExecutorRegular(this, ActiveRegular, Config)));
    }
    WatchDog->Start();
}
