#include <maps/wikimap/mapspro/services/mrc/libs/toloka_manager/include/image_quality_classification.h>
#include <maps/libs/json/include/builder.h>
#include <maps/libs/json/include/std.h>
#include <maps/libs/json/include/value.h>

#include <algorithm>
#include <map>

namespace maps {
namespace mrc {
namespace toloka {

namespace {

std::map<std::string, ImageQualityC12nAnswer> IMAGE_QUALITY_C12N_ANSWERS_MAP
    = {{"ok", ImageQualityC12nAnswer::Ok},
       {"has-defect", ImageQualityC12nAnswer::HasDefect},
       {"not-loaded", ImageQualityC12nAnswer::NotLoaded}};

ImageQualityC12nAnswer parseImageQualityC12nAnswer(const json::Value& value)
{
    const auto answer = value.as<std::string>();
    auto itr = IMAGE_QUALITY_C12N_ANSWERS_MAP.find(answer);
    REQUIRE(itr != IMAGE_QUALITY_C12N_ANSWERS_MAP.end(),
            "Invalid image quality classification answer: " << answer);
    return itr->second;
}

} // anonymous namespace

void ImageQualityC12nInput::json(json::ObjectBuilder builder) const
{
    builder[FIELD_IMAGE] = imageUrl();
}

template <>
ImageQualityC12nInput parseJson(const json::Value& jsonInput)
{
    auto imageUrl = jsonInput[FIELD_IMAGE].as<std::string>();
    return {imageUrl};
}

void ImageQualityC12nOutput::json(json::ObjectBuilder builder) const
{
    auto it = std::find_if(
        IMAGE_QUALITY_C12N_ANSWERS_MAP.begin(),
        IMAGE_QUALITY_C12N_ANSWERS_MAP.end(),
        [this](const std::pair<std::string, ImageQualityC12nAnswer>& p) {
            return p.second == answer_;
        });
    REQUIRE(it != IMAGE_QUALITY_C12N_ANSWERS_MAP.end(),
            "Invalid image quality classification answer_ value");
    builder[FIELD_STATE] = it->first;
}

template <>
ImageQualityC12nOutput parseJson(const json::Value& jsonOutput)
{
    ImageQualityC12nAnswer answer
        = parseImageQualityC12nAnswer(jsonOutput[FIELD_STATE]);
    return {answer};
}

/**
 * ImageQualityC12nInput implementation
 */

ImageQualityC12nInput::ImageQualityC12nInput(std::string imageUrl)
    : imageUrl_(std::move(imageUrl))
{
}

const std::string& ImageQualityC12nInput::imageUrl() const
{
    return imageUrl_;
}

ImageQualityC12nInput& ImageQualityC12nInput::setImageUrl(std::string url)
{
    imageUrl_ = url;
    return *this;
}

/**
 * ImageQualityC12nOutput implementation
 */

ImageQualityC12nOutput::ImageQualityC12nOutput(ImageQualityC12nAnswer answer)
    : answer_(answer)
{
}

ImageQualityC12nAnswer ImageQualityC12nOutput::answer() const
{
    return answer_;
}

bool operator==(const ImageQualityC12nOutput& lhs, const ImageQualityC12nOutput& rhs)
{
    return lhs.introspect() == rhs.introspect();
}

bool operator<(const ImageQualityC12nOutput& lhs, const ImageQualityC12nOutput& rhs)
{
    return lhs.introspect() < rhs.introspect();
}

std::ostream& operator<<(std::ostream& out, const ImageQualityC12nOutput& taskOutput)
{
    json::Builder builder(out);
    builder << [&](json::ObjectBuilder b) {
        taskOutput.json(b);
    };
    return out;
}

} // namespace toloka
} // namespace mrc
} // namespace maps
