#include "script.h"

#include <saas/deploy_manager/meta/cluster.h>
#include <saas/deploy_manager/modules/resources/resources.h>
#include <saas/deploy_manager/scripts/cluster/cluster_task.h>
#include <saas/deploy_manager/scripts/common/deploy/deploy_builder.h>
#include <saas/deploy_manager/scripts/common/scripts_helper.h>
#include <saas/deploy_manager/server/client/client.h>
#include <saas/util/external/dc.h>
#include <saas/util/external/diff.h>
#include <library/cpp/json/json_reader.h>
#include <util/string/type.h>

namespace {

    void ParseEndpoints(const TString& epsStr, TVector<NSearchMapParser::TSearchMapHost>& deletedEpsAsSearchMapHosts) {
        TVector<TString> endpoints = SplitString(epsStr, ",");

        //cluster@eps.name
        for (size_t i=0; i<endpoints.size(); ++i) {
            NRTYCluster::TSlotData slotData(endpoints[i], 80);
            NSearchMapParser::TSearchMapHost smh(slotData.FullHost(), TInterval<NSearchMapParser::TShardIndex>(), NSearchMapParser::Master, slotData.Port, slotData.IndexPort());
            smh.IsSd = true;
            deletedEpsAsSearchMapHosts.push_back(smh);
        }
    }
}

namespace NRTYDeploy {

    bool TScriptReleaseEndpointSets::Process(IDeployInfoRequest& request) {
        TClusterTask::TCgiContext context = TClusterTask::TCgiContext::Parse(request.GetRD().CgiParam);
        if (request.GetRD().CgiParam.Get("action") != "release") {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "&action=release missing";
            return false;
        }
        TString epsStr = request.GetRD().CgiParam.Get("eps");
        // format: &eps=dc@eps1
        TVector<NSearchMapParser::TSearchMapHost> deletedEndpointSets;

        try {
            ParseEndpoints(epsStr, deletedEndpointSets);
        } catch (yexception&) {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "Cannot parse endpointsets: " << CurrentExceptionMessage();
            return false;
        }
        if (deletedEndpointSets.size() == 0) {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "No endpointsets found in &eps= " ;
            return false;
        }

        const TString& ctype = context.CType;
        const TString& service = context.Service;
        const TString& serviceType = context.ServiceType;

        NRTYDeployInfo::IDeployComponentInfo::TPtr info = NRTYDeployInfo::IDeployComponentInfo::TFactory::Construct(serviceType);
        info->SetInfo(&request, ctype);
        NRTYDeployInfo::IDeployServiceInfo::TPtr serviceInfo = info->BuildServiceInfo(service);

        NSaas::TClusterLocker clusterPtr = NSaas::TClusterLocker::DefineMutable(request, ctype);
        if (!clusterPtr) {
            request.Output() << "HTTP/1.1 500 \r\n\r\n";
            request.Output() << "Resource " << "/common/" << ctype << "/cluster.meta is not available for modification";
            return false;
        }
        SetData(clusterPtr.GetContent(), "");

        NRTYCluster::TCTypeCluster cluster;

        auto&& clusterInfo = request.GetCommonData().GetResourcesManager().GetCluster(serviceType, service);

        if (!clusterInfo.GetCTypeCluster(ctype, cluster)) {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "Incorrect ctype: " << ctype;
            return false;
        }

        NSearchMapParser::TSlotsPool poolResult;

        for (auto&& smh : deletedEndpointSets) {
            poolResult.Add(smh);
        }

        serviceInfo->CorrectTopology(request.GetRD().CgiParam, &poolResult, *clusterPtr);

        TString errorMessage;
        if (!clusterPtr->Validate(errorMessage)) {
            DEBUG_LOG << "Can't store cluster meta: " << errorMessage << Endl;
            request.Output() << "HTTP/1.1 500 \r\n\r\n";
            request.Output() << "Incorrect new cluster: " << errorMessage;
            return false;
        }
        SetData("", clusterPtr.GetContent());
        if (!clusterPtr.Save()) {
            request.Output() << "HTTP/1.1 500 \r\n\r\n";
            request.Output() << "Incorrect storage structure";
            return false;
        }
        request.Output() << "HTTP/1.1 200 \r\n\r\n";
        request.Output() << poolResult.Serialize().GetStringRobust();

        return true;
    };

    IScript::TFactory::TRegistrator<TScriptReleaseEndpointSets> TScriptReleaseEndpointSets::Registrator("release_endpointsets");
}
