#include "script.h"
#include <saas/deploy_manager/server/client/client.h>

#include <saas/deploy_manager/meta/cluster.h>
#include <saas/library/searchmap/parsers/parser.h>
#include <saas/library/searchmap/searchmap.h>

namespace NRTYDeploy {

    bool Smap2ClusterMeta(const TString& searchMapString, const TString service,
        NSearchMapParser::TSearchMapService& serviceMap, TString& error) {

        try {
            auto parser = NSearchMapParser::OpenSearchMap(searchMapString);
            NSearchMapParser::TSearchMap searchMap = parser->GetSearchMap();
            if (searchMap.HasService(service)) {
                serviceMap = *searchMap.GetService(service);
                return true;
            } else {
                error = "no service '" + service + "' in incoming searchmap";
            }
        } catch (const yexception& e) {
            error = e.what();
        }
        return false;
    }

    bool TExternalClusterScript::Process(IDeployInfoRequest& request) {
        TString action = request.GetRD().CgiParam.Get("action");
        if (action == "set") {
            TString source = request.GetRD().CgiParam.Get("source");
            TString ctype = request.GetRD().CgiParam.Get("ctype");
            TString service = request.GetRD().CgiParam.Get("service");
            if (!service || !ctype) {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << "Empty service or ctype";
                return false;
            }

            bool gotSearchmapSuccess = false;
            NSearchMapParser::TSearchMapService serviceMap;
            TString error;

            if (source == "post") {
                const TBlob& fileData = request.GetBlob();
                DEBUG_LOG << "POST data size = " << fileData.Length() << Endl;
                const TString searchMapString(fileData.AsCharPtr(), fileData.Length());

                bool res = Smap2ClusterMeta(searchMapString, service, serviceMap, error);
                if (res) {
                    gotSearchmapSuccess = true;
                } else {
                    request.Output() << "HTTP/1.1 400 \r\n\r\n";
                    request.Output() << "Error while processing input: " << error << "\r\n";
                }
            } else {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << "Searchmap obtaining from '" << source << "' not supported\r\n";
            }
            if (!gotSearchmapSuccess) {
                return false;
            }
            serviceMap.Name = 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(), "");

            clusterPtr->AddRTYService(serviceMap);

            if (!clusterPtr->Validate(error)) {
                DEBUG_LOG << "Can't store cluster meta: " << error << Endl;
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << "Incorrect new cluster: " << error;
                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 Ok\r\n\r\n";
            return true;
        } else {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "Unknown action: '" << action << "'\r\n";
        }
        return true;
    }

    IScript::TFactory::TRegistrator<TExternalClusterScript> TExternalClusterScript::Registrator("external_cluster");
}
