#include <yandex/maps/wiki/unittest/json_schema.h>

#include <library/cpp/testing/unittest/env.h>
#include <yandex/maps/shell_cmd.h>
#include <maps/libs/common/include/file_utils.h>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <iostream>

namespace fs = boost::filesystem;
using namespace std::string_literals;
using namespace boost::algorithm;

namespace maps::wiki::unittest {

namespace {
const std::string JSON_VALIDATOR = BinaryPath("maps/tools/json-validator/json-validator");

const auto EXAMPLE = ".example"s;
const auto JSON_EXT = ".json"s;
const auto SCHEMA = ".schema"s;

std::string
guessSchemaPath(const std::string& schemasDir, const std::string& exampleName)
{
    std::string schemaName = exampleName;
    if (boost::algorithm::contains(exampleName, EXAMPLE)) {
        boost::replace_all(schemaName, EXAMPLE, SCHEMA);
    } else {
        if (boost::algorithm::ends_with(exampleName, JSON_EXT)) {
            boost::replace_all(schemaName, JSON_EXT, SCHEMA + JSON_EXT);
        }
    }

    schemaName = schemasDir + "/" + schemaName;
    auto fsObject = fs::path(schemaName);
    REQUIRE(fs::exists(fsObject) && fs::is_regular_file(fsObject),
        "Failed to guess schema for: " << exampleName
        << "\n Tried: " << schemaName);
    return schemaName;
}

} // namespace

void
validateJson(const std::string& jsonString, const std::string& schemaPath)
{
    auto command = JSON_VALIDATOR + " -s " + schemaPath;
    auto result = maps::shell::runCmd(command, jsonString, std::chrono::milliseconds(-1));
    REQUIRE(result.exitCode == 0, "json-validator failed:"
                << "\n stdOut: " << result.stdOut
                << "\n stdErr: " << result.stdErr);
}

void validateJsonDir(const std::string& examplesDir, const std::string& schemasDir)
{
    for (const auto& entry : fs::directory_iterator(examplesDir)) {
        if (!fs::is_regular_file(entry.status())) {
            continue;
        }
        const auto exampleName = entry.path().filename();
        if (exampleName.extension() != JSON_EXT) {
            continue;
        }
        const auto schemaPath = guessSchemaPath(schemasDir, exampleName.string());
        std::cerr << "Validating " << exampleName << " against " << schemaPath << std::endl;
        const auto exampleJson = maps::common::readFileToString(entry.path().string());
        validateJson(exampleJson, schemaPath);
    }
}

} // namespace maps::wiki::unittest

