#include "format.h"

#include <util/string/vector.h>

TYasmAlert::TYasmAlert(const TString& golovanId, const TString& signal, const TString& itype)
    : GolovanId(golovanId)
    , Signal(signal)
    , RealTags(TMap<TString, TString>())
    , Limits(0, 0, 0)
{
    RealTags["itype"] = itype;
}

TAlertLimits::TAlertLimits(const double warn, const double crit, const ui16 avgsec)
    : Warn(warn)
    , Crit(crit)
    , Avgsec(avgsec)
{};

TYasmAlert& TYasmAlert::SetLimits(const double warn, const double crit, const ui16 avgsec) {
    Limits = TAlertLimits(warn, crit, avgsec);
    return *this;
}

TYasmAlert& TYasmAlert::AddRealTag(const TString& tagName, const TString& tagValue) {
    RealTags[tagName] = tagValue;
    return *this;
}

NJson::TJsonValue TAlertLimits::ToJson() const {
    NJson::TJsonValue result(NJson::JSON_MAP);
    if (Warn <= Crit) {
        result["warn"] = NJson::TJsonValue(NJson::JSON_ARRAY);
        result["warn"].AppendValue(Warn);
        result["warn"].AppendValue(Crit);
        result["crit"] = NJson::TJsonValue(NJson::JSON_ARRAY);
        result["crit"].AppendValue(Crit);
        result["crit"].AppendValue(NJson::TJsonValue(NJson::JSON_NULL));
    } else {
        result["warn"] = NJson::TJsonValue(NJson::JSON_ARRAY);
        result["warn"].AppendValue(Crit);
        result["warn"].AppendValue(Warn);
        result["crit"] = NJson::TJsonValue(NJson::JSON_ARRAY);
        result["crit"].AppendValue(NJson::TJsonValue(NJson::JSON_NULL));
        result["crit"].AppendValue(Crit);
    }
    if (Avgsec) {
        result["value_modify"] = NJson::TJsonValue(NJson::JSON_MAP);
        result["value_modify"]["type"] = "aver";
        result["value_modify"]["window"] = Avgsec;
    }
    return result;
}

NJson::TJsonValue TYasmAlert::ToJson() const {
    NJson::TJsonValue result(NJson::JSON_MAP);
    result["name"] = GolovanId;
    result["signal"] = Signal;
    result["mgroups"] = NJson::TJsonValue(NJson::JSON_ARRAY);
    result["mgroups"].AppendValue("ASEARCH");
    result["tags"] = NJson::TJsonValue(NJson::JSON_MAP);
    for (const auto& it : RealTags) {
        result["tags"][it.first] = it.second;
    }
    NJson::TJsonValue limitsJs = Limits.ToJson();
    for (auto& i : limitsJs.GetMap()) {
        result[i.first] = i.second;
    }
    return result;
}

TString TYasmAlert::ToString() const {
    NJson::TJsonValue result = ToJson();
    TStringStream ss;
    NJson::WriteJson(&ss, &result);
    return ss.Str();
}

TExistingAlert::TExistingAlert(const NJson::TJsonValue& json, const TString& alertsPrefix)
    : Json(json)
{
    const TString& name = json["name"].GetString();
    if (!name.StartsWith(alertsPrefix)) {
        return;
    }
    TVector<TString> parts = SplitString(name.substr(alertsPrefix.length() + 1), ".");
    if (parts.ysize() < 3) {
        return;
    }
    Ctype = parts[0];
    Service = parts[1];
    AKey = parts[parts.ysize() - 1];
}

bool TExistingAlert::GetLimits(double& warn, double& crit, ui16& avgsec, TString& message) const {
    const NJson::TJsonValue& critArr = Json["crit"];
    const NJson::TJsonValue& warnArr = Json["warn"];
    if (critArr.GetArray().ysize() != 2 || warnArr.GetArray().ysize() != 2) {
        message = "wrong limits arr sizes";
        return false;
    }
    //possible cases: crit=[2, null] warn=[1, 2] crit>warn; crit=[null, 1] warn=[1, 2] crit<warn;
    if (critArr.GetArray()[0].IsDouble()) {
        crit = critArr.GetArray()[0].GetDouble();
        warn = warnArr.GetArray()[0].GetDouble();
        if (crit < warn) {
            message = "something wrong with limits format, case crit[0]";
            return false;
        }
    } else {
        crit = critArr.GetArray()[1].GetDouble();
        warn = warnArr.GetArray()[1].GetDouble();
        if (crit > warn) {
            message = "something wrong with limits format, case crit[1]";
            return false;
        }
    }
    avgsec = 0;
    if (Json.Has("value_modify")) {
        avgsec = Json["value_modify"]["window"].GetUInteger();
    }
    return true;
}
