#include "fbapi_task_wrapper.h"
#include <maps/libs/common/include/exception.h>

namespace maps::wiki::fbapi_social_tool {

namespace {

std::vector<geolib3::Point2> loadEntrances(const json::Value& entrances)
{
    std::vector<geolib3::Point2> result;
    for (const auto& entrance : entrances) {
        const auto& point = entrance["center_point"];
        REQUIRE(point.exists(), "Can not find entrance center_point");
        const auto& lon = point["lon"];
        REQUIRE(lon.exists(), "Can not find entrance center_point/lon");
        const auto& lat = point["lat"];
        REQUIRE(lon.exists(), "Can not find entrance center_point/lat");

        result.emplace_back(lon.as<double>(), lat.as<double>());
    }
    return result;
}

} // namespace

FbapiTaskWrapper::FbapiTaskWrapper(const json::Value& originalTask)
    : originalTask_(originalTask)
{
    REQUIRE(originalTask_.isObject(), "Original task is not object type");
}

std::string FbapiTaskWrapper::companyId() const
{
    const auto& companyId = getValue("object_id");
    REQUIRE(companyId.exists(), "No permalink");
    return companyId.toString();
}

geolib3::Point2 FbapiTaskWrapper::position() const
{
    const auto& ansX = getValue({"answer_context", "company", "coordinates", "lon"});
    const auto& ansY = getValue({"answer_context", "company", "coordinates", "lat"});
    ASSERT(ansX.exists() == ansY.exists());

    const auto& qX = getValue({"question_context", "company", "coordinates", "lon"});
    const auto& qY = getValue({"question_context", "company", "coordinates", "lat"});
    ASSERT(qX.exists() == qY.exists());

    REQUIRE(ansX.exists() || qX.exists(), "Can not find geo position: lon");
    REQUIRE(ansY.exists() || qY.exists(), "Can not find geo position: lat");

    return geolib3::Point2(
        ansX.exists() ? ansX.as<double>() : qX.as<double>(),
        ansY.exists() ? ansY.as<double>() : qY.as<double>());
}

std::string FbapiTaskWrapper::comment() const
{
    const auto& message = getValue("message");
    if (!message.exists()) {
        return {};
    }
    return message.as<std::string>();
}

std::vector<std::string> FbapiTaskWrapper::attachedPhotos() const
{
    const auto& photos = getValue("attached_photos");
    if (!photos.exists()) {
        return {};
    }
    REQUIRE(photos.isArray(), "Attached photos are not array type");
    std::vector<std::string> result;
    for (const auto& photo : photos) {
        result.emplace_back(photo.as<std::string>());
    }
    return result;
}

std::vector<geolib3::Point2> FbapiTaskWrapper::entrances() const
{
    const auto& ansEntrances = getValue({"answer_context", "company", "entrances"});
    if (ansEntrances.exists()) {
        return loadEntrances(ansEntrances);
    }

    const auto& qEntrances = getValue({"question_context", "company", "entrances"});
    if (qEntrances.exists()) {
        return loadEntrances(qEntrances);
    }
    return {};
}

const json::Value& FbapiTaskWrapper::getValue(const std::vector<std::string>& path) const
{
    const json::Value* current = &originalTask_;
    for (const auto& key : path) {
        if (!current->exists()) {
            break;
        }
        current = &(*current)[key];
    }
    return *current;
}

const json::Value& FbapiTaskWrapper::getValue(const std::string& path) const
{
    return getValue(std::vector<std::string>{path});
}

} // namespace maps::wiki::fbapi_social_tool
