#include "task.h"
#include "action.h"
#include <saas/deploy_manager/meta/cluster.h>
#include <saas/deploy_manager/scripts/add_slots/action.h>
#include <saas/deploy_manager/scripts/allocate_slots/action/action_replica.h>
#include <saas/deploy_manager/scripts/allocate_slots/common/intervals.h>
#include <saas/deploy_manager/scripts/common/dead_slots_collector/dead_slots_collector.h>
#include <saas/deploy_manager/scripts/common/deploy/deploy_builder.h>
#include <saas/deploy_manager/scripts/restore_index/action.h>
#include <saas/deploy_manager/scripts/searchmap/action.h>
#include <saas/deploy_manager/storage/abstract.h>

namespace NRTYDeploy {

    TAddReplicaTask::TAddReplicaTask(ui32 slotsCount, const NRTYCluster::TSlotsAllocator& slotsAllocator,
        const TClusterTask::TCgiContext& context, NRTYDeploy::ICommonData* commonData,
        ui32 replicasCount, bool restore, bool allocateOnly, bool deployProxy, float mayBeDeadIntervalPercentage)
        : TClusterTask(context, commonData, ADD_REPLICA_TASK_TYPE)
        , SlotsAllocator(slotsAllocator)
        , SlotsCount(slotsCount)
        , ReplicasCount(replicasCount)
        , Restore(restore)
        , AllocateOnly(allocateOnly)
        , DeployProxy(deployProxy)
        , MayBeDeadIntervalPercentage(mayBeDeadIntervalPercentage)
    {
    }

    TString TAddReplicaTask::GetReportConstruction() const {
        NJson::TJsonValue reply(NJson::JSON_MAP);
        reply.InsertValue("id_task", GetId());
        return reply.GetStringRobust();
    }

    void TAddReplicaTask::DoBuildTask() {

        NRTYDeployInfo::IDeployComponentInfo::TPtr info = NRTYDeployInfo::IDeployComponentInfo::TFactory::Construct(ServiceType);
        if (!info) {
            SetStatus(ctsFailed, TClusterTask::rsFailedOnConstruction, "Incorrect service type: " + ServiceType);
            return;
        }
        info->SetInfo(CommonData, CType);
        auto ism = info->SearchMap(Service);

        NSearchMapParser::TSearchMapService* serviceObj = ism.GetService(Service);
        if (!serviceObj) {
            SetStatus(ctsFailed, TClusterTask::rsFailedOnConstruction, "Can't read service \"" + Service + "\"");
            return;
        }
        NSearchMapParser::TSearchMapReplica* replicaDef = serviceObj->GetReplica("default");

        NDaemonController::TIntervalsByDC intervalsByDC;
        if (!SlotsCount) {
            if (replicaDef && replicaDef->GetSlots().size() > 0) {
                for (auto&& i : replicaDef->GetSlots()) {
                    intervalsByDC.AddInfoUniq("*", i.Shards);
                }
            } else {
                SetStatus(ctsFailed, TClusterTask::rsFailedOnConstruction, "Ethalon-replic not detected");
                return;
            }
        } else {
            for (ui32 i = 0; i < SlotsCount; ++i) {
                TInterval<NSearchMapParser::TShardIndex> shards = NSaas::TSharding::GetInterval(i, SlotsCount, 0, serviceObj->GetShardsMax());
                intervalsByDC.AddInfo("*", shards);
            }
        }

        NDaemonController::TAction::TPtr actionModifySearchMap = new NDaemonController::TAllocateSlotsReplicasAction(intervalsByDC, ReplicasCount, SlotsAllocator, Service, CType, RTYSERVER_SERVICE);
        auto currentTask = GetScript()->AddAction(CommonData->GetDeployManagerBalanserHost(), CommonData->GetDeployManagerBalanserPort(), CommonData->GetDeployManagerBalanserUriPrefix(), actionModifySearchMap);

        if (!AllocateOnly) {

            const TString slotsPoolAddress(TString::Join('$', currentTask.GetName(), "-action.task.result_pool"));

            NDaemonController::TAction::TPtr actionAddSlots = new NDaemonController::TActivateSlotsAction(slotsPoolAddress, CType, Service, ServiceType);

            NDaemonController::TAction::TPtr actionRestore;
            if (Restore && replicaDef && replicaDef->GetSlots().size()) {
                actionRestore = new NRTYDeploy::TRestoreIndexAction(Service, CType, TDeadSlotsCollector::GetNotUsefulSlots(Service, CommonData, ism),
                    slotsPoolAddress, NDaemonController::apStartAndWait);
            }
            NDaemonController::TAction::TPtr actionActivateSlots = new NDaemonController::TSimpleSearchmapModifAction(slotsPoolAddress, CType, Service,
                "enable_search,enable_indexing", ServiceType, true, DeployProxy, MayBeDeadIntervalPercentage);

            currentTask.AddNext(*GetScript(), actionAddSlots).AddNext(*GetScript(), actionRestore).AddNext(*GetScript(), actionActivateSlots);
        }
    }
};
