#include "deploy_info.h"
#include "task.h"

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

#include <library/cpp/regex/pcre/regexp.h>

#include <util/string/type.h>

namespace NRTYDeploy {

    class TClearCallback: public NJson::IScanCallback {
    private:
        THolder<TRegExMatch> ExlusionMatcher;
        THolder<TRegExMatch> InclusionMatcher;
    public:

        TClearCallback(const TString& exRegexPath, const TString& incRegexPath) {
            if (exRegexPath) {
                ExlusionMatcher = MakeHolder<TRegExMatch>();
                ExlusionMatcher->Compile(exRegexPath);
            }
            if (incRegexPath) {
                InclusionMatcher = MakeHolder<TRegExMatch>();
                InclusionMatcher->Compile(incRegexPath);
            }
        }

        bool Do(const TString& path, NJson::TJsonValue* /*parent*/, NJson::TJsonValue& value) override {
            if (path && (ExlusionMatcher && ExlusionMatcher->Match(path.data()) || InclusionMatcher && !InclusionMatcher->Match(path.data()))) {
                NJson::TJsonValue val("removed");
                value.Swap(val);
                return false;
            }
            return true;
        }
    };

    void TScriptDeployInfo::FillUsedResources(IUserAccessControl::TUsedResources& result, IDeployInfoRequest& request) {
        if (request.GetRD().CgiParam.Has("id"))
            return;
        if (request.GetRD().CgiParam.Has("service"))
            result.Services.insert(request.GetRD().CgiParam.Get("service"));
        else
            result.Services.insert("all_services");
    }

    NJson::TJsonValue TScriptDeployInfo::GetTaskInfo(const TClusterTask& task) {
        NJson::TJsonValue value = task.Serialize();
        if (!!ExclusionFilter || !!InclusionFilter) {
            TClearCallback clear = TClearCallback(ExclusionFilter, InclusionFilter);
            value.Scan(clear);
        }
        return value;
    }

    bool TScriptDeployInfo::Process(IDeployInfoRequest& request) {
        try {
            ExclusionFilter = request.GetRD().CgiParam.Get("exclusion_filter");
            InclusionFilter = request.GetRD().CgiParam.Get("inclusion_filter");
            if (request.GetRD().CgiParam.Has("id")) {
                TString id = request.GetRD().CgiParam.Get("id");
                if (request.GetRD().CgiParam.Get("wait_only") == "yes") {
                    TVector<TString> tasks;
                    if (!request.GetQueue().GetTasks("deploy", id, tasks) || !tasks.size()) {
                        TClusterTask task(id, &request, 16);
                        if (task.GetCurrentStatus() == TClusterTask::ctsLoaded) {
                            request.Output() << "HTTP/1.1 200 \r\n\r\n";
                            request.Output() << NJson::WriteJson(GetTaskInfo(task));
                            return true;
                        } else {
                            request.Output() << "HTTP/1.1 400 \r\n\r\n";
                            request.Output() << "Can't load task: " << task.GetStatusInfo() << "/" << RSToString(task.GetResultStatus());
                            return true;
                        }
                    } else {
                        NJson::TJsonValue reply(NJson::JSON_MAP);
                        reply.InsertValue("is_finished", false);
                        request.Output() << "HTTP/1.1 200 \r\n\r\n";
                        request.Output() << reply.GetStringRobust();
                        return true;
                    }
                } else {
                    TClusterTask task(id, &request, 16);
                    if (task.GetCurrentStatus() == TClusterTask::ctsLoaded) {
                        request.Output() << "HTTP/1.1 200 \r\n\r\n";
                        request.Output() << NJson::WriteJson(GetTaskInfo(task));
                        return true;
                    } else {
                        request.Output() << "HTTP/1.1 400 \r\n\r\n";
                        request.Output() << "Can't load task: " << task.GetStatusInfo() << "/" << RSToString(task.GetResultStatus());
                        return true;
                    }
                }
            } else if (request.GetRD().CgiParam.Has("service")) {
                const TString service = request.GetRD().CgiParam.Get("service");
                TString subQueueRegex;
                if (!!service) {
                    subQueueRegex = service + "-";
                    const TString ctype = request.GetRD().CgiParam.Get("ctype");
                    if (!!ctype) {
                        subQueueRegex += ctype + "-";
                    }
                }
                subQueueRegex += ".*";
                TVector<TString> tasks;
                request.GetQueue().GetTasks("deploy", subQueueRegex, tasks);

                NJson::TJsonValue json(NJson::JSON_MAP);
                json.InsertValue("failed", NJson::JSON_ARRAY);
                NJson::TJsonValue& activeTasks = json.InsertValue("active", NJson::JSON_MAP);
                for (const TString& task : tasks)
                    activeTasks.InsertValue(task.substr(0, task.size() - 10), "ok");

                TStringStream ss;
                NJson::WriteJson(&ss, &json, true, false, false);

                request.Output() << "HTTP/1.1 200 \r\n\r\n";
                request.Output() << ss.Str();
                return true;
            } else {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << "id or service must be in request";
                return true;
            }
        }
        catch (...) {
            request.Output() << "HTTP/1.1 500 \r\n\r\n";
            request.Output() << CurrentExceptionMessage() << Endl;
            return false;
        }
    }

    IScript::TFactory::TRegistrator<TScriptDeployInfo> TScriptDeployInfo::Registrator("deploy_info");
}
