#include "script.h"
#include "alerts_logic.h"
#include "alerts_config.h"

#include <saas/deploy_manager/modules/juggler/format.h>
#include <saas/deploy_manager/modules/juggler/module.h>
#include <saas/deploy_manager/modules/golovan/format.h>
#include <saas/deploy_manager/modules/golovan/module.h>
#include <saas/deploy_manager/scripts/common/alerts/remove.h>
#include <saas/deploy_manager/server/client/client.h>

#include <library/cpp/json/json_writer.h>
#include <util/string/type.h>

using namespace NRTYAlerts;

namespace NRTYDeploy {

    void AnswerWithJson(IDeployInfoRequest& request, const TString& code, const NJson::TJsonValue& json) {
        request.Output() << "HTTP/1.1 " << code << " \r\n\r\n";
        TStringStream ss;
        NJson::WriteJson(&ss, &json, true, true, false);
        request.Output() << ss.Str();
    }

    bool TScriptAlerts::Process(IDeployInfoRequest& request) {
        bool alertsEnabled = request.GetCommonData().GetConfig().GetAlertsConfig().GetEnabled();
        if (!alertsEnabled) {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "Alerts disabled for this dm";
            return false;
        }
        TString action = request.GetRD().CgiParam.Get("action");
        TString service = request.GetRD().CgiParam.Get("service");
        TString ctype = request.GetRD().CgiParam.Get("ctype");
        TString akey = request.GetRD().CgiParam.Get("akey");
        TString what = request.GetRD().CgiParam.Get("what");
        bool dryRun = IsTrue(request.GetRD().CgiParam.Get("dry"));

        bool doJuggler = !what || what.Contains("juggler");
        bool doGolovan = !what || what.Contains("golovan");
        if (!doGolovan && !doJuggler) {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "unknown 'what=' param value";
        }
        bool jSuccess = false, gSuccess = false;

        if (action == "list") {
            NJson::TJsonValue result(NJson::JSON_MAP);
            TMap<TString, TString> filter = JugglerFilter(service, ctype, akey);
            if (doJuggler) {
                NJson::TJsonValue& juggResult = result.InsertValue("checks", NJson::JSON_MAP);
                jSuccess = request.GetCommonData().GetJugglerModule().GetAllChecks(juggResult, filter);
            }
            if (doGolovan) {
                NJson::TJsonValue& yasmResult = result.InsertValue("alerts", NJson::JSON_MAP);
                gSuccess = request.GetCommonData().GetGolovanModule().GetAlerts(filter, yasmResult);
            }
            bool success = (doJuggler ? jSuccess : true) && (doGolovan ? gSuccess : true);
            TString code = success ? "200" : "500";
            AnswerWithJson(request, code, result);
            return success;

        } else if (action == "get_conf") {
            NJson::TJsonValue result(NJson::JSON_MAP);
            NJson::TJsonValue& conf = result.InsertValue("conf", NJson::JSON_MAP);
            NJson::TJsonValue& confParts = result.InsertValue("conf_parts", NJson::JSON_MAP);
            NJson::TJsonValue& aKeys = result.InsertValue("akeys", NJson::JSON_MAP);
            bool success = GetAlertsServiceOptions(service, ctype, request, conf, aKeys, confParts);
            TString code = success ? "200" : "500";
            AnswerWithJson(request, code, result);
            return success;
        } else if (action == "create") {
            TAlertsMaker maker(service, ctype, request);
            if (!maker.IsValid()) {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << maker.GetErrorMessage() << " ctype=" << ctype << " service=" << service;
                return false;
            }
            NJson::TJsonValue result(NJson::JSON_MAP);
            if (doGolovan) {
                gSuccess = maker.CreateYasmAlert(akey, result.InsertValue("alerts", NJson::JSON_MAP));
            }
            if (doJuggler && (gSuccess || !doGolovan)) {
                jSuccess = maker.CreateJugglerCheck(akey, result.InsertValue("checks", NJson::JSON_MAP), dryRun);
            }
            bool success = (doJuggler ? jSuccess : true) && (doGolovan ? gSuccess : true);
            TString code = success ? "200" : "400";
            AnswerWithJson(request, code, result);
            return success;
        } else if (action == "remove") {
            TString jugglerId = request.GetRD().CgiParam.Get("juggler_id");
            TString tag = request.GetRD().CgiParam.Get("tag");
            TString jugglerHost = request.GetRD().CgiParam.Get("juggler_host");
            TString golovanId = request.GetRD().CgiParam.Get("golovan_id");
            NJson::TJsonValue result(NJson::JSON_MAP);
            bool success;
            if (!!golovanId) {
                doGolovan = true;
                doJuggler = false;
                gSuccess = request.GetCommonData().GetGolovanModule().RemoveAlert(golovanId, result);
            } else if (!!jugglerId) {
                doJuggler = true;
                doGolovan = false;
                jSuccess = request.GetCommonData().GetJugglerModule().RemoveCheck(jugglerId, tag, jugglerHost, result);
            } else if (!!service) {
                TMap<TString, TString> filter = JugglerFilter(service, ctype, akey);
                if (doJuggler) {
                    NJson::TJsonValue& juggResult = result.InsertValue("checks", NJson::JSON_MAP);
                    jSuccess = RemoveChecksByFilter(request.GetCommonData(), filter, juggResult);
                }
                if (doGolovan) {
                    NJson::TJsonValue& yasmResult = result.InsertValue("alerts", NJson::JSON_MAP);
                    gSuccess = RemoveAlertsByFilter(request.GetCommonData(), filter, yasmResult);
                }
            } else {
                success = false;
                result["error"] = "must be either check id(juggler service) or saas service in cgi";
            }
            success = (doJuggler ? jSuccess : true) && (doGolovan ? gSuccess : true);
            TString code = success ? "200" : "400";
            request.Output() << "HTTP/1.1 " << code << " \r\n\r\n";
            TStringStream ss;
            NJson::WriteJson(&ss, &result, true, true, false);
            request.Output() << ss.Str();
        } else if (action == "check") {
            TAlertsMaker maker(service, ctype, request);
            if (!maker.IsValid()) {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << maker.GetErrorMessage() << " ctype=" << ctype << " service=" << service;
                return false;
            }
            NJson::TJsonValue result(NJson::JSON_MAP);

            bool success = maker.GetFullServiceActuality(result);
            TString code = success ? "200" : "500";
            AnswerWithJson(request, code, result);
            return success;
        } else if (action == "actualize_list") {
            TAlertsMaker maker(service, ctype, request);
            if (!maker.IsValid()) {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << maker.GetErrorMessage() << " ctype=" << ctype << " service=" << service;
                return false;
            }
            NJson::TJsonValue result(NJson::JSON_MAP);
            NJson::TJsonValue& lists = result.InsertValue("statuses", NJson::JSON_MAP);
            NJson::TJsonValue checks, alerts;
            if (!maker.GetExceedingMissingKeys(lists, checks, alerts)) {
                result["dry_run"] = true;
                AnswerWithJson(request, "500", lists);
                return false;
            }
            if (dryRun) {
                AnswerWithJson(request, "200", lists);
                return true;
            }
            NJson::TJsonValue& done = result.InsertValue("done", NJson::JSON_MAP);
            bool success = maker.ActualizeExceedingMissingKeys(lists, done);

            TString code = success ? "200" : "500";
            AnswerWithJson(request, code, result);
            return success;
        } else if (action == "actualize") {
            TAlertsMaker maker(service, ctype, request);
            if (!maker.IsValid()) {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << maker.GetErrorMessage() << " ctype=" << ctype << " service=" << service;
                return false;
            }
            NJson::TJsonValue result(NJson::JSON_MAP);
            bool existingOnly = IsTrue(request.GetRD().CgiParam.Get("existing_only"));

            bool success = maker.ActualizeFullService(existingOnly, result, dryRun);
            TString code = success ? "200" : "400";
            AnswerWithJson(request, code, result);
            return success;
        } else if (action == "clear_left") {
            NJson::TJsonValue result(NJson::JSON_MAP);
            bool success = ClearNotExistingServices(request, result, dryRun);

            TString code = success ? "200" : "500";
            request.Output() << "HTTP/1.1 " << code << " \r\n\r\n";
            TStringStream ss;
            NJson::WriteJson(&ss, &result, true, true, false);
            request.Output() << ss.Str();
            return success;
        } else {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "Not implemented " << action;
            return false;
        }
        return true;
    }
    IScript::TFactory::TRegistrator<TScriptAlerts> TScriptAlerts::Registrator("process_alerts");
}
