#include <yandex/maps/wiki/tasks/task_info.h>

namespace maps {
namespace wiki {
namespace tasks {

namespace {

const std::string ID_ATTR = "id";
const std::string STATUS_ATTR = "status";
const std::string TYPE_ATTR = "type";
const std::string CREATED_ATTR = "created";

const std::string TASK_LIST_XPATH = "/t:tasks/t:task-list";
const std::string TASK_XPATH = "/t:tasks/t:task";
const std::string TOKEN_XPATH = "/t:tasks/t:internal/t:token";

/**
 * \see
 * /mapscore/wikimap/mapspro/libs/python/pymod/yandex/maps/wiki/tasks/states.py
 *
 *    PENDING = 'PENDING'
 *    STARTED = 'STARTED'
 *    SUCCESS = 'SUCCESS'
 *    FAILURE = 'FAILURE'
 *    REVOKED = 'REVOKED'
 *    FROZEN = 'FROZEN'
 *
 * \code
 * /mapscore/wikimap/mapspro/schemas/tasks$ grep 'status' *.xml
 * \endcode
 *
 *    "failure"
 *    "frozen"
 *    "pending"
 *    "revoked"
 *    "started"
 *    "success"
 */
const std::map<std::string, TaskStatus> STATUSES = {
    {"pending", TaskStatus::InProgress},
    {"started", TaskStatus::InProgress},
    {"frozen", TaskStatus::Frozen},
    {"success", TaskStatus::Success},
};

TaskStatus translateTaskStatus(const std::string& status)
{
    auto it = STATUSES.find(status);
    if (it != STATUSES.end()) {
        return it->second;
    }
    return TaskStatus::Failed;
}

const xml3::Namespaces XML_NAMESPACES
    = {{"t", "http://maps.yandex.ru/mapspro/tasks/1.x"}};

void addNamespaces(xml3::Doc& doc)
{
    for (const auto& ns : XML_NAMESPACES) {
        doc.addNamespace(ns.first, ns.second);
    }
}

} // namespace

TaskInfo::TaskInfo(const maps::xml3::Node& node, Token token)
    : id_(node.attr<TaskId>(ID_ATTR))
    , status_(translateTaskStatus(node.attr<std::string>(STATUS_ATTR)))
    , type_(node.attr<std::string>(TYPE_ATTR))
    , createdAt_(node.attr<std::string>(CREATED_ATTR))
    , token_(std::move(token))
{}

TaskInfo TaskInfo::fromXml(const std::string& xml)
{
    auto doc = xml3::Doc::fromString(xml);
    addNamespaces(doc);

    auto tokenNode = doc.node(TOKEN_XPATH, true);
    auto token = tokenNode.isNull() ? Token() : tokenNode.value<Token>();

    return TaskInfo(doc.node(TASK_XPATH), std::move(token));
}

TaskInfos TaskInfo::listFromXml(const std::string& xml)
{
    TaskInfos taskInfos;

    auto doc = xml3::Doc::fromString(xml);
    addNamespaces(doc);
    auto taskList = doc.node(TASK_LIST_XPATH);
    auto node = taskList.firstElementChild();
    while (!node.isNull()) {
        taskInfos.emplace_back(node);
        node = node.nextElementSibling();
    }
    return taskInfos;
}

} // namespace tasks
} // namespace wiki
} // namespace maps
