#include "script.h"
#include "task.h"
#include <saas/deploy_manager/meta/cluster.h>
#include <saas/deploy_manager/scripts/common/scripts_helper.h>
#include <saas/deploy_manager/scripts/common/deploy/deploy_builder.h>
#include <saas/deploy_manager/server/client/client.h>
#include <saas/util/external/diff.h>

#include <library/cpp/json/json_reader.h>

#include <util/string/type.h>

namespace NRTYDeploy {

    bool TScriptModifySearchmap::Process(IDeployInfoRequest& request) {
        const TCgiParameters& cgiParams = request.GetRD().CgiParam;
        const TClusterTask::TCgiContext context = TClusterTask::TCgiContext::Parse(cgiParams);
        const TString& slots = cgiParams.Get("slots");
        const TString& slotsVector = cgiParams.Get("slots_vector");
        if (!!slots && !!slotsVector) {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "Incorrect slots info slots and slots_vector in time";
            return false;
        }
        const TString& ctype = context.CType;
        const TString& service = context.Service;
        const TString& action = cgiParams.Get("action");
        const TString& serviceType = context.ServiceType;

        NSearchMapParser::TSlotsPool slotsPool;
        if (!!slots) {
            if (!slotsPool.DeserializeFromString(slots)) {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << "Incorrect slots info " << slots;
                return false;
            }
        } else {
            if (action == "add" || action == "add_int")
                ythrow yexception() << "add must be called with full slots pool";
            slotsPool.Parse(SplitString(slotsVector, ","));
        }

        if (IsTrue(cgiParams.Get("deploy"))) {
            try {
                const bool deployProxies = !cgiParams.Has("deploy_proxies") || IsTrue(cgiParams.Get("deploy_proxies"));
                float mayBeDeadIntervalPercentage = 0.5f;
                if (cgiParams.Has("may_be_dead_procentage")) {
                    mayBeDeadIntervalPercentage = FromString<float>(cgiParams.Get("may_be_dead_procentage"));
                }
                TModifySearchmapTask task(slotsPool, action, context, &request, deployProxies, mayBeDeadIntervalPercentage);
                for (const auto& val: cgiParams.Range("interval")) {
                    TVector<TString> intervals = SplitString(val, ";");
                    for (const TString& intervalStr : intervals) {
                        TVector<TString> fromTo = SplitString(intervalStr, "->");
                        if (fromTo.size() != 2)
                            ythrow yexception() << "incorrect interval " << intervalStr;
                        task.ReplaceInterval(fromTo[0], fromTo[1]);
                    }
                }
                task.BuildTask();
                if (task.GetCurrentStatus() == TClusterTask::ctsEnqueued) {
                    request.Output() << "HTTP/1.1 200 \r\n\r\n";
                    request.Output() << task.GetId() << Endl;
                } else if (task.GetResultStatus() == TClusterTask::rsDuplication) {
                    request.Output() << "HTTP/1.1 400 \r\n\r\n";
                    request.Output() << "duplication" << Endl;
                } else {
                    request.Output() << "HTTP/1.1 500 \r\n\r\n";
                    request.Output() << "Fail code: " << RSToString(task.GetResultStatus()) << ". Message: " << task.GetStatusInfo();
                }
            } catch (yexception& e) {
                request.Output() << "HTTP/1.1 500 \r\n\r\n";
                request.Output() << "Build and enqueue failed: " << e.what();
            }
        } else {
            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(), "");
            serviceInfo->CorrectTopology(cgiParams, &slotsPool, *clusterPtr);
            TString errorMessage;
            if (!clusterPtr->Validate(errorMessage)) {
                DEBUG_LOG << "Can't store cluster meta: " << errorMessage << Endl;
                request.Output() << "HTTP/1.1 400 \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() << clusterPtr.GetContent();
        }

        return true;
    };

    IScript::TFactory::TRegistrator<TScriptModifySearchmap> TScriptModifySearchmap::Registrator("modify_searchmap");
}
