#include <maps/wikimap/mapspro/services/tasks_realtime/src/publication_check_worker/lib/garden.h>

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

#include <fmt/format.h>
#include <regex>
#include <string_view>
#include <unordered_set>
#include <unordered_map>

using namespace maps;
using namespace maps::wiki;

namespace {

constexpr std::string_view MODULE_TEMPLATE = "../data/{}.json";
constexpr std::string_view BUILD_INFOS_PATH = "../data/ymapsdf_src_builds.json";
const std::string GARDEN_BUILD_INFO_REGEX =
            "^http://core-garden-server.maps.yandex.net/modules/(.*?)/build_statistics/(\\d*?)/$";

const std::unordered_set<std::string_view> MODULES = {
    "carparks_activation",
    "export_cams",
    "masstransit_deployment",
    "geocoder_deployment",
    "road_graph_deployment",
    "renderer_deployment",
};

const auto FROM_TIME = chrono::parseIsoDateTime("2020-07-13T00:00:00Z");

class TestHttpClient : public garden::IHttpClient
{
public:
    TestHttpClient() : BuildsInfos{std::move(maps::json::Value::fromFile(SRC_(BUILD_INFOS_PATH)))} {
        for (const auto& module: MODULES) {
            Urls_[fmt::format(garden::GARDEN_MODULES_STATISTICS, module, chrono::formatIsoDateTime(FROM_TIME))]
                = fmt::format(MODULE_TEMPLATE, module);
        }
    }

    maps::json::Value get(const std::string& url) override
    {
        if (Urls_.count(url) > 0) {
            return maps::json::Value::fromFile(SRC_(Urls_[url]));
        }

        std::regex r(GARDEN_BUILD_INFO_REGEX);
        std::smatch m;
        std::regex_search(url, m, r);

        if (m.size() == 3 and m[1].str() == garden::MODULE_YMAPSDF_SRC) {
            return BuildsInfos[m[2].str()];
        }

        UNIT_FAIL("Wrong URL " << url);
        return maps::json::null; // unreachable code
    }

private:
    std::unordered_map<std::string, std::string> Urls_;
    maps::json::Value BuildsInfos;
};

} // namespace

#define DATA_HAS_EVENT_FOR_BRANCH(data, event, region, branchId) \
do { \
    std::string regionEvent = std::string{region}.empty() ? event : event + ":" + region; \
    const auto it = data.find(regionEvent); \
    UNIT_ASSERT(it != data.end()); \
    const auto& branchToTime = it->second; \
    UNIT_ASSERT_VALUES_EQUAL(branchToTime.size(), 1); \
    UNIT_ASSERT_VALUES_EQUAL(branchToTime.begin()->first, branchId); \
} while (false)

Y_UNIT_TEST_SUITE(test_publication_check_worker_local)
{

Y_UNIT_TEST(test_garden_pedestrian_graph)
{
    TestHttpClient httpClient;

    auto eventHolder = garden::loadBranchDeployedTimes(httpClient, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, FROM_TIME);
    const auto& data = eventHolder.data();
    UNIT_ASSERT_VALUES_EQUAL(data.size(), 10);

    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "aao", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "cis1", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "cis2", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "eu1", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "eu3", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "eu4", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "na", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "saa", 1632);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_PEDESTRIAN_GRAPH, "tr", 1632);
}

Y_UNIT_TEST(test_garden_mtr_export)
{
    TestHttpClient httpClient;

    auto eventHolder = garden::loadBranchDeployedTimes(httpClient, EVENT_DEPLOYED_MTR_EXPORT, FROM_TIME);
    const auto& data = eventHolder.data();
    UNIT_ASSERT_VALUES_EQUAL(data.size(), 2);

    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_MTR_EXPORT, "", 1631);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_MTR_EXPORT, "cis1", 1631);
}

Y_UNIT_TEST(test_garden_geocoder_deployment_different_branch)
{
    TestHttpClient httpClient;

    auto eventHolder = garden::loadBranchDeployedTimes(httpClient, EVENT_DEPLOYED_GEOCODER, FROM_TIME);
    const auto& data = eventHolder.data();
    UNIT_ASSERT_VALUES_EQUAL(data.size(), 3);

    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_GEOCODER, "", 1234);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_GEOCODER, "cis1", 1234);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_GEOCODER, "tr", 1632);
}

Y_UNIT_TEST(test_garden_road_graph_deployment_deploy_steps)
{
    TestHttpClient httpClient;

    auto eventHolder = garden::loadBranchDeployedTimes(httpClient, EVENT_DEPLOYED_GRAPH, FROM_TIME);
    const auto& data = eventHolder.data();
    UNIT_ASSERT_VALUES_EQUAL(data.size(), 3);

    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_GRAPH, "", 1234);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_GRAPH, "cis1", 1234);
    DATA_HAS_EVENT_FOR_BRANCH(data, EVENT_DEPLOYED_GRAPH, "tr", 1234);
}

} //Y_UNIT_TEST_SUITE
