#pragma once

#include <maps/wikimap/mapspro/services/mrc/libs/common/include/image_box.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/toloka/task.h>
#include <maps/wikimap/mapspro/services/mrc/libs/toloka_manager/include/known_solution.h>
#include <maps/libs/json/include/builder.h>
#include <maps/libs/json/include/value.h>
#include <yandex/maps/mrc/traffic_signs/signs.h>

#include <vector>

namespace maps::mrc::toloka {

traffic_signs::TrafficSign parseTrafficSignId(const std::string& name);

// Uses json::prettifyJson to minimize the string
std::string minifyJson(std::string jsonString);

// Functions to serialize/deserialize task Input/Output values

template <typename T>
std::string toJson(const T& value)
{
    json::Builder builder;
    builder << value;
    return builder.str();
}

template <typename T>
T parseJson(const json::Value& value);

template <typename T>
T parseJson(const std::string& str)
{
    return parseJson<T>(json::Value::fromString(str));
}

// Json serialization and parse functions for KnownSolution(s)

template <typename TaskType>
KnownSolution<TaskType> parseKnownSolutionJson(const json::Value& value)
{
    auto outputValues
        = parseJson<OutputType<TaskType>>(value["output_values"]);
    auto correctnessWeight = value["correctness_weight"].as<double>();
    return {outputValues, correctnessWeight};
}

template <typename TaskType>
KnownSolution<TaskType> parseKnownSolutionJson(const std::string& str)
{
    auto jsonInput = json::Value::fromString(str);
    return parseKnownSolutionJson<TaskType>(jsonInput);
}

template <typename TaskType>
std::string toJson(const KnownSolutions<TaskType>& solutions)
{
    json::Builder builder;
    builder << solutions;
    return builder.str();
}

template <typename TaskType>
KnownSolutions<TaskType> parseKnownSolutionsJson(const std::string& str)
{
    KnownSolutions<TaskType> knownSolutions;

    auto jsonKnownSolutions = json::Value::fromString(str);
    REQUIRE(jsonKnownSolutions.isArray(), "Invalid Known solutions format");
    for (const auto& jsonKnownSolution : jsonKnownSolutions) {
        knownSolutions.push_back(
            parseKnownSolutionJson<TaskType>(jsonKnownSolution));
    }
    return knownSolutions;
}

} // namespace maps::mrc::toloka
