#include "plainer_inserter.h"

namespace NPrivate {

    bool TGroupInserter::SlotIsAccepted(const NJson::TJsonValue& slot, const NJson::TJsonValue* checkConfigResult) {
        const auto& res = slot["result"];
        ui64 ss = res["slot_size"].GetUIntegerRobust();
        ui64 sc = res["slots_count"].GetUIntegerRobust();
        ui64 tms = res["total_mem_size"].GetUIntegerRobust() / (1024 * 1024 * 1024);
        if (tms != 0 && sc * ss > tms + 1)
            return true;
        double la = res["load_average"].GetDoubleRobust();
        ui64 cc = res["cpu_count"].GetUIntegerRobust();
        if (!cc)
            cc = 10;
        if (la >= 3 * cc)
            return true;
        if (res["controller_status"].GetStringRobust() != "Active")
            return true;
        if (MinOkUptime != TDuration::Zero() && res.Has("controller_uptime")) {
            TDuration uptime;
            const NJson::TJsonValue& uptimeJson = res["controller_uptime"];
            if (uptimeJson.IsString())
                uptime = FromString<TDuration>(uptimeJson.GetString());
            else
                uptime = TDuration::Seconds(uptimeJson.GetUIntegerRobust());
            if (uptime < MinOkUptime)
                return true;
        }

        if (checkConfigResult)
            for (const auto& file : checkConfigResult->GetMap())
                if (file.second["from_host"].GetStringRobust() != file.second["last_deployed"].GetStringRobust())
                    return true;
        return false;
    }

    void TGroupInserter::InsertValuePlain(NJson::TJsonValue& result, const TString& key, const NJson::TJsonValue& value) {
        switch (value.GetType()) {
        case NJson::JSON_ARRAY:
            for (size_t i = 0; i < value.GetArray().size(); ++i)
                InsertValuePlain(result, key + (!!key ? "." : "") + ToString(i), value.GetArray()[i]);
            break;
        case NJson::JSON_MAP:
            for (const auto& i : value.GetMap())
                InsertValuePlain(result, key + (!!key ? "." : "") + i.first, i.second);
            break;
        default:
            result.InsertValue(key, value);
        }
    }

    NJson::TJsonValue* TGroupInserter::Insert(const NJson::TJsonValue& source) {
        if (OnlyProblem && !AcceptedHosts.contains(source["host"].GetStringRobust()))
            return nullptr;
        NJson::TJsonValue* toInsert = &Report;
        for (const auto& gr : Groupings)
            toInsert = &(*toInsert)[source[gr].GetStringRobust()];
        NJson::TJsonValue& inserted = toInsert->AppendValue(NJson::JSON_MAP);
        InsertValuePlain(inserted, "", source);
        return &inserted;
    }

    TGroupInserter::TGroupInserter(NJson::TJsonValue& report, const TVector<TString> groupings, bool onlyProblem, const NJson::TJsonValue& getInfoActionResult, const NJson::TJsonValue& checkConfigResult, TDuration minOkUptime)
        : Report(report)
        , Groupings(groupings)
        , OnlyProblem(onlyProblem)
        , MinOkUptime(minOkUptime)
    {
        if (OnlyProblem) {
            for (const auto& service : getInfoActionResult.GetMap())
                for (const auto& slot : service.second.GetMap())
                    if (SlotIsAccepted(slot.second, checkConfigResult.GetValueByPath(service.first + "." + slot.first, '.')))
                        AcceptedHosts.insert(SplitString(slot.first, ":").front());
        }
    }
}
