#include "grouping.h"

#include <saas/deploy_manager/scripts/interface/dashboard_util/plainer.h>
#include <saas/deploy_manager/scripts/interface/dashboard_util/plainer_inserter.h>
#include <saas/deploy_manager/scripts/interface/dashboard_util/plainer_richers.h>

#include <saas/library/sharding/sharding.h>
#include <saas/util/types/interval.h>

#include <library/cpp/json/json_writer.h>
#include <library/cpp/testing/unittest/registar.h>

using namespace NPrivate;

Y_UNIT_TEST_SUITE(TGrouingReportTest) {

    static TInterval<NSearchMapParser::TShardIndex> Interval(const NSearchMapParser::TShardIndex min, const NSearchMapParser::TShardIndex max) {
        return TInterval<NSearchMapParser::TShardIndex>(min, max);
    }

    static void AddHost(const TString& service , const TString& host, const TString& dc, const TInterval<NSearchMapParser::TShardIndex>& interval,
        const ui32 docsInFinal, const ui32 docsInMem, const ui32 filesSize, NJson::TJsonValue& response)
    {
        NJson::TJsonValue& hostJson = response[service][host];
        hostJson["$datacenter$"] = dc;
        hostJson["$datacenter_alias$"] = dc;
        hostJson["disable_search"] = "false";
        hostJson["interval"] = interval.ToString();
        hostJson["service"] = service;
        hostJson["result"]["docs_in_final_indexes"] = docsInFinal;
        hostJson["result"]["docs_in_memory_indexes"] = docsInMem;
        hostJson["result"]["files_size"] = NJson::JSON_MAP;
        hostJson["result"]["files_size"]["__SUM"] = filesSize;
        hostJson["result"]["controller_status"] = "Active";
    }

    static void AddFailedHost(const TString& service , const TString& host, const TString& dc, const TInterval<NSearchMapParser::TShardIndex>& interval,
        NJson::TJsonValue& response)
    {
        NJson::TJsonValue& hostJson = response[service][host];
        hostJson["$datacenter$"] = dc;
        hostJson["$datacenter_alias$"] = dc;
        hostJson["disable_search"] = "false";
        hostJson["interval"] = interval.ToString();
        hostJson["service"] = service;
    }

    static NJson::TJsonValue GenerateTestReply() {
        NJson::TJsonValue res;

        AddHost("service1", "msk11.search.yandex.net:8888", "MSK", Interval(0, 21843), 76647614, 14768, 999, res);
        AddHost("service1", "msk21.search.yandex.net:8888", "MSK", Interval(0, 21843), 76144679, 56676, 1000, res);
        AddHost("service1", "man21.search.yandex.net:8888", "MAN", Interval(0, 21843), 76147862, 54530, 1076, res);
        AddHost("service1", "man11.search.yandex.net:8888", "MAN", Interval(0, 21843), 76640852, 34372, 1000, res);
        AddHost("service1", "sas11.search.yandex.net:8888", "SAS", Interval(0, 21843), 76483597, 66830, 1030, res);
        AddHost("service1", "sas21.search.yandex.net:8888", "SAS", Interval(0, 21843), 76190775, 10592, 1024, res);

        AddHost("service1", "msk31.search.yandex.net:8888", "MSK", Interval(21844, 43687), 76660624, 6513, 2000, res);
        AddHost("service1", "msk41.search.yandex.net:8888", "MSK", Interval(21844, 43687), 76353641, 34502, 1013, res);
        AddHost("service1", "man31.search.yandex.net:8888", "MAN", Interval(21844, 43687), 76178360, 29047, 989, res);
        AddHost("service1", "man41.search.yandex.net:8888", "MAN", Interval(21844, 43687), 76674586, 11727, 989, res);
        AddHost("service1", "sas31.search.yandex.net:8888", "SAS", Interval(21844, 43687), 76796892, 76492, 996, res);
        AddHost("service1", "sas41.search.yandex.net:8888", "SAS", Interval(21844, 43687), 76135467, 69945, 595, res);

        AddHost("service1", "msk51.search.yandex.net:8888", "MSK", Interval(43688, 65533), 76634519, 23702, 1023, res);
        AddHost("service1", "msk61.search.yandex.net:8888", "MSK", Interval(43688, 65533), 76188888, 11238, 1057, res);
        AddHost("service1", "man51.search.yandex.net:8888", "MAN", Interval(43688, 65533), 76447371, 50489, 990, res);
        AddHost("service1", "man21.search.yandex.net:8888", "MAN", Interval(43688, 65533), 76652855, 11124, 1011, res);
        AddHost("service1", "sas51.search.yandex.net:8888", "SAS", Interval(43688, 65533), 76165960, 34484, 1003, res);
        AddHost("service1", "sas61.search.yandex.net:8888", "SAS", Interval(43688, 65533), 77137378, 69167, 1007, res);


        AddHost("service2", "msk12.search.yandex.net:8888", "MSK", Interval(0, 65533), 2552, 0, 823, res);
        AddHost("service2", "sas12.search.yandex.net:8888", "SAS", Interval(0, 65533), 1552, 0, 813, res);
        AddHost("service2", "man12.search.yandex.net:8888", "MAN", Interval(0, 65533), 552, 0, 800, res);

        AddHost("service3", "msk12.search.yandex.net:8889", "MSK", Interval(0, 65533), 2550, 0, 913, res);
        AddFailedHost("service3", "sas12.search.yandex.net:8889", "SAS", Interval(0, 65533), res);
        AddHost("service3", "man12.search.yandex.net:8889", "MAN", Interval(0, 65533), 553, 0, 13, res);

        return res;
    }

    static THashMap<TString, NJson::TJsonValue> RunDefaultTest(const TString& cgiStr) {
         NJson::TJsonValue r = GenerateTestReply();
         const TCgiParameters cgi(cgiStr);
        NJson::TJsonValue report;
        TGroupReporter reporter(cgi);
        TIntrusivePtr<NPrivate::TRicherReplicsConsistanse> replicsConsistance = MakeIntrusive<NPrivate::TRicherReplicsConsistanse>();

        TString categories = "service.slot";
        NPrivate::TPlainer plainer(new NPrivate::TGroupInserter(report, reporter.GetGroupings(), false, r, NJson::TJsonValue(), TDuration::Zero()), categories);
        replicsConsistance->InitializeByBroadcastResult(r);
        plainer.AddPredInsertRicher(replicsConsistance);
        plainer.Process(r);

        NJson::TJsonValue newReport;
        reporter.Report(newReport, report);
        report = newReport;

        UNIT_ASSERT(report.IsArray());
        UNIT_ASSERT_VALUES_EQUAL(report.GetArray().size(), 3);

        THashMap<TString, NJson::TJsonValue> byService;
        for (const auto& v: report.GetArray()) {
            byService[v["id"].GetString()] = v;
        }

        UNIT_ASSERT(byService.contains("service1"));
        UNIT_ASSERT(byService["service1"]["inconsistent_replics_ratio"].IsDouble());
        UNIT_ASSERT_DOUBLES_EQUAL(byService["service1"]["inconsistent_replics_ratio"].GetDouble(), 0., 1e-5);
        UNIT_ASSERT(byService["service1"]["replics_consistance"].IsNull());

        UNIT_ASSERT(byService["service1"]["size_inconsistent_replics_ratio"].IsDouble());
        UNIT_ASSERT_DOUBLES_EQUAL(byService["service1"]["size_inconsistent_replics_ratio"].GetDouble(), 1./3, 1e-5);
        UNIT_ASSERT(byService["service1"].Has("size_replics_consistance"));
        UNIT_ASSERT(byService["service1"]["size_replics_consistance"]["shortage_size"].IsUInteger());
        UNIT_ASSERT_VALUES_EQUAL(byService["service1"]["size_replics_consistance"]["shortage_size"].GetUInteger(), 1);
        UNIT_ASSERT(byService["service1"]["size_replics_consistance"]["overage_size"].IsUInteger());
        UNIT_ASSERT_VALUES_EQUAL(byService["service1"]["size_replics_consistance"]["overage_size"].GetUInteger(), 1);

        UNIT_ASSERT(byService.contains("service2"));
        UNIT_ASSERT(byService["service2"]["inconsistent_replics_ratio"].IsDouble());
        UNIT_ASSERT_DOUBLES_EQUAL(byService["service2"]["inconsistent_replics_ratio"].GetDouble(), 2./3, 1e-5);
        UNIT_ASSERT(byService["service2"].Has("replics_consistance"));
        UNIT_ASSERT(byService["service2"]["replics_consistance"]["shortage_docs"].IsUInteger());
        UNIT_ASSERT_VALUES_EQUAL(byService["service2"]["replics_consistance"]["shortage_docs"].GetUInteger(), 1);
        UNIT_ASSERT(byService["service2"]["replics_consistance"]["overage_docs"].IsUInteger());
        UNIT_ASSERT_VALUES_EQUAL(byService["service2"]["replics_consistance"]["overage_docs"].GetUInteger(), 1);

        UNIT_ASSERT(byService["service2"]["size_inconsistent_replics_ratio"].IsDouble());
        UNIT_ASSERT_DOUBLES_EQUAL(byService["service2"]["size_inconsistent_replics_ratio"].GetDouble(), 0., 1e-5);
        UNIT_ASSERT(byService["service2"]["size_replics_consistance"].IsNull());
        return byService;
    }

    Y_UNIT_TEST(TestOldReportGroupings) {
        RunDefaultTest("plain_report=yes&filter=replics_consistance"
            "&groupings=service(replics_consistance@facet,inconsistent_replics_ratio@max,"
            "size_replics_consistance@facet,size_inconsistent_replics_ratio@max"
            ");interval@(inconsistent_replics_ratio@summ,size_inconsistent_replics_ratio@summ)"
            "&report_slots=no");
    };

   Y_UNIT_TEST(TestReportGroupingsWithDocCount) {
       THashMap<TString, NJson::TJsonValue> byService = RunDefaultTest("plain_report=yes&filter=replics_consistance"
            "&groupings=service(replics_consistance@facet,inconsistent_replics_ratio@max,"
                "size_replics_consistance@facet,size_inconsistent_replics_ratio@max,"
                "docs_count_min@summ,docs_count_max@summ);"
                "interval@(inconsistent_replics_ratio@summ,size_inconsistent_replics_ratio@summ,"
                "docs_count_max=docs_count@max,docs_count_min=docs_count@min,"
                "index_size_max=result.files_size.__SUM@max,index_size_min=result.files_size.__SUM@min)"
            "&report_slots=no");

        UNIT_ASSERT(byService["service1"]["docs_count_min"].IsUInteger());
        UNIT_ASSERT(byService["service1"]["docs_count_max"].IsUInteger());
        UNIT_ASSERT_VALUES_EQUAL(byService["service1"]["docs_count_min"].GetUInteger(), 228606893);
        UNIT_ASSERT_VALUES_EQUAL(byService["service1"]["docs_count_max"].GetUInteger(), 230755153);

        UNIT_ASSERT(byService["service2"]["docs_count_min"].IsUInteger());
        UNIT_ASSERT(byService["service2"]["docs_count_max"].IsUInteger());
        UNIT_ASSERT_VALUES_EQUAL(byService["service2"]["docs_count_min"].GetUInteger(), 552);
        UNIT_ASSERT_VALUES_EQUAL(byService["service2"]["docs_count_max"].GetUInteger(), 2552);

        UNIT_ASSERT(byService["service3"]["docs_count_min"].IsUInteger());
        UNIT_ASSERT(byService["service3"]["docs_count_max"].IsUInteger());
        UNIT_ASSERT_VALUES_EQUAL(byService["service3"]["docs_count_min"].GetUInteger(), 553);
        UNIT_ASSERT_VALUES_EQUAL(byService["service3"]["docs_count_max"].GetUInteger(), 2550);

    };

    Y_UNIT_TEST(TestReportGroupingsUnknownAggregation) {
         THashMap<TString, NJson::TJsonValue> byService = RunDefaultTest("plain_report=yes&filter=replics_consistance"
            "&groupings=service(replics_consistance@facet,inconsistent_replics_ratio@max,"
            "size_replics_consistance@facet,size_inconsistent_replics_ratio@max);"
            "interval@(inconsistent_replics_ratio@summ,size_inconsistent_replics_ratio@summ,docs_count_unknown=docs_count@unknown_aggregation)"
            "&report_slots=no");
    };

}
