#include "task_consistency.h"

#include <yandex/maps/wiki/social/common.h>
#include <yandex/maps/wiki/social/feedback/attribute_names.h>
#include <yandex/maps/wiki/social/feedback/attributes.h>
#include <yandex/maps/wiki/social/feedback/task.h>
#include <yandex/maps/wiki/social/feedback/task_new.h>
#include <maps/libs/common/include/exception.h>

#include <boost/lexical_cast.hpp>
#include <optional>
#include <exception>

using boost::lexical_cast;

namespace maps::wiki::social::feedback {

namespace {

/* Speed limit task */

bool isSpeedlimitTask(const TaskNew& task)
{
    return task.type == Type::RoadSpeedLimit;
}

bool speedLimitIsConsistent(
    const std::optional<TId>& objectId,
    const Attrs& attrs)
{
    try {
        lexical_cast<int>(attrs.getCustom(attrs::CORRECT_SPEED_LIMIT));

        /* Speed-limit feedback from MRC may not have current speed limit on road */

        if (attrs.existCustom(attrs::CURRENT_SPEED_LIMIT)) {
            lexical_cast<int>(attrs.getCustom(attrs::CURRENT_SPEED_LIMIT));
        }
    } catch (const std::exception&) {
        return false;
    }

    return objectId != std::nullopt;
}

/* Route lost task */

bool isRouteLostTask(const TaskNew& task)
{
    return task.type == Type::RouteLost;
}

bool routeLostIsConsistent(const Attrs& attrs)
{
    try {
        const auto& userAttrs = attrs.get(AttrType::UserData);

        userAttrs[attrs::BEFORE_LOST_SEGMENT][attrs::EDGE_ID].as<uint64_t>();
        userAttrs[attrs::BEFORE_LOST_SEGMENT][attrs::SEGMENT_ID].as<uint64_t>();

        userAttrs[attrs::AFTER_LOST_ROUTE_SEGMENT][attrs::EDGE_ID].as<uint64_t>();
        userAttrs[attrs::AFTER_LOST_ROUTE_SEGMENT][attrs::SEGMENT_ID].as<uint64_t>();

        userAttrs[attrs::AFTER_LOST_TRACK_SEGMENT][attrs::EDGE_ID].as<uint64_t>();
        userAttrs[attrs::AFTER_LOST_TRACK_SEGMENT][attrs::SEGMENT_ID].as<uint64_t>();

    } catch (const std::exception&) {
        return false;
    }

    return true;
}

} // anonymous

void requireTaskAndAttrsConsistency(const TaskNew& task)
{
    if (isSpeedlimitTask(task)) {
        requireSpeedLimitConsistency(task);
    }
    if (isRouteLostTask(task)) {
        requireRouteLostConsistency(task);
    }
    /*
        add types and its consistency checkers here
    */
}

void requireSpeedLimitConsistency(const Task& task)
{
    REQUIRE(speedLimitIsConsistent(task.objectId(), task.attrs()),
        "Attributes of speed-limit feedback Task are inconsistent");
}

void requireSpeedLimitConsistency(const TaskNew& task)
{
    REQUIRE(speedLimitIsConsistent(task.objectId, task.attrs),
        "Attributes of speed-limit feedback TaskNew are inconsistent");
}

void requireRouteLostConsistency(const Task& task)
{
    REQUIRE(routeLostIsConsistent(task.attrs()),
        "Attributes of route lost feedback Task are inconsistent");
}

void requireRouteLostConsistency(const TaskNew& task)
{
    REQUIRE(routeLostIsConsistent(task.attrs),
        "Attributes of route lost feedback TaskNew are inconsistent");
}

} // namespace maps::wiki::social::feedback
