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

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

namespace {

constexpr const char* STATE = "state";
constexpr const char* STATE_LIST = "state_list";
constexpr const char* TASK_ID = "taskId";
constexpr const char* USER_ID = "workerId";

} // namespace

// Tolokers results

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

NYT::TNode TolokersResult::toYTNode() const {
    NYT::TNode node = bld.toYTNode();
    node[RESULT_ID] = id;
    NYT::TNode stateList = NYT::TNode::CreateList();
    for (const auto& [userId, userState] : userStates) {
        stateList.Add(
            NYT::TNode()
            (USER_ID, TString(userId))
            (STATE, TString(toString(userState)))
        );
    }
    node[STATE_LIST] = stateList;
    node[STATE] = TString(toString(state));
    node[TASK_ID] = TString(taskId);
    return node;
}

void TolokersResult::toJson(json::ObjectBuilder& builder) const {
    bld.toJson(builder);
    builder[RESULT_ID] = id;
    builder[STATE_LIST] = [&](json::ArrayBuilder b) {
        for (size_t i = 0; i < userStates.size(); i++) {
            b << [&](json::ObjectBuilder b) {
                b[USER_ID] = userStates[i].first;
                b[STATE] = toString(userStates[i].second);
            };
        }
    };
    builder[STATE] = toString(state);
    builder[TASK_ID] = taskId;
}

TolokersResult TolokersResult::fromYTNode(const NYT::TNode& node) {
    TolokersResult result;
    result.id = node[RESULT_ID].AsUint64();
    result.bld = Building::fromYTNode(node);
    NYT::TNode::TListType stateList = node[STATE_LIST].AsList();
    for (const NYT::TNode& stateNode : stateList) {
        std::string userId = stateNode[USER_ID].AsString();
        TolokaState userState;
        fromString(stateNode[STATE].AsString().data(), userState);
        result.userStates.emplace_back(userId, userState);
    }
    fromString(node[STATE].AsString().data(), result.state);
    result.taskId = node[TASK_ID].AsString();
    return result;
}

TolokersResult TolokersResult::fromJson(const json::Value& value) {
    TolokersResult result;
    result.id = value[RESULT_ID].as<uint64_t>();
    result.bld = Building::fromJson(value);
    for (const json::Value& stateJson : value[STATE_LIST]) {
        std::string userId = stateJson[USER_ID].as<std::string>();
        TolokaState userState;
        fromString(stateJson[STATE].as<std::string>(), userState);
        result.userStates.emplace_back(userId, userState);
    }
    fromString(value[STATE].as<std::string>(), result.state);
    result.taskId = value[TASK_ID].as<std::string>();
    return result;
}

NYT::TTableSchema TolokersResult::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(STATE_LIST, NYT::EValueType::VT_ANY)
        .AddColumn(TASK_ID, NYT::EValueType::VT_STRING)
        .AddColumn(STATE, NYT::EValueType::VT_STRING)
        .AddColumn(DUMP_DATE, NYT::EValueType::VT_STRING)
        .Strict(false);
}

bool TolokersResult::operator==(const TolokersResult& that) const {
    return id == that.id
        && bld == that.bld
        && userStates == that.userStates
        && state == that.state
        && taskId == that.taskId;
}

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