#include <maps/wikimap/mapspro/services/autocart/pipeline/libs/objects/include/building.h>
#include <maps/wikimap/mapspro/services/autocart/pipeline/libs/storage/include/publication_results.h>
#include <maps/wikimap/mapspro/services/autocart/pipeline/libs/storage/include/strings.h>

#include <maps/libs/enum_io/include/enum_io.h>

#include <unordered_map>

using namespace std::string_view_literals;

namespace maps::wiki::autocart::pipeline {

namespace {

constexpr const char* PUBLICATION_STATUS = "publication_status";

const std::unordered_map<PublicationStatus, int> STATUS_CODES{
    {PublicationStatus::Published, 0},
    {PublicationStatus::Intersects, 1},
    {PublicationStatus::Error, 2}
};

} // namespace

PublicationStatus decodePublicationStatus(int value) {
    for (const auto& [status, code] : STATUS_CODES) {
        if (code == value) {
            return status;
        }
    }
    throw maps::RuntimeError("Invalid publication status code: " + std::to_string(value));
}

int encodePublicationStatus(const PublicationStatus& status) {
    return STATUS_CODES.at(status);
}

const std::string& PublicationResult::getName() {
    static const std::string NAME = "publication";
    return NAME;
}

NYT::TNode PublicationResult::toYTNode() const {
    NYT::TNode node = bld.toYTNode();
    node[RESULT_ID] = id;
    node[PUBLICATION_STATUS] = encodePublicationStatus(status);
    return node;
}

void PublicationResult::toJson(json::ObjectBuilder& builder) const {
    bld.toJson(builder);
    builder[RESULT_ID] = id;
    builder[PUBLICATION_STATUS] = encodePublicationStatus(status);
}

PublicationResult PublicationResult::fromYTNode(const NYT::TNode& node) {
    PublicationResult result;
    result.id = node[RESULT_ID].AsUint64();
    result.bld = Building::fromYTNode(node);
    result.status = decodePublicationStatus(node[PUBLICATION_STATUS].AsInt64());
    return result;
}

PublicationResult PublicationResult::fromJson(const json::Value& value) {
    PublicationResult result;
    result.id = value[RESULT_ID].as<uint64_t>();
    result.bld = Building::fromJson(value);
    result.status = decodePublicationStatus(value[PUBLICATION_STATUS].as<uint64_t>());
    return result;
}

NYT::TTableSchema PublicationResult::getTableSchema() {
    return NYT::TTableSchema()
        .AddColumn(REGION, NYT::EValueType::VT_STRING, NYT::ESortOrder::SO_ASCENDING)
        .AddColumn(ISSUE_ID, NYT::EValueType::VT_UINT64, NYT::ESortOrder::SO_ASCENDING)
        .AddColumn(RESULT_ID, NYT::EValueType::VT_UINT64)
        .AddColumn(PUBLICATION_STATUS, NYT::EValueType::VT_INT64)
        .AddColumn(DUMP_DATE, NYT::EValueType::VT_STRING)
        .Strict(false);
}

bool PublicationResult::operator==(const PublicationResult& that) const {
    return id == that.id
        && bld == that.bld
        && status == that.status;
}

} // namespace maps::wiki::autocart::pipeline

