#include <maps/wikimap/mapspro/services/social_backoffice/src/api/globals.h>

#include <maps/wikimap/mapspro/services/social_backoffice/src/lib/hypothesis.h>
#include <maps/wikimap/mapspro/services/social_backoffice/src/lib/yacare.h>

#include <maps/wikimap/mapspro/services/social/src/libs/yacare/helpers.h>

#include <maps/wikimap/mapspro/libs/social/include/yandex/maps/wiki/social/feedback/gateway_ro.h>
#include <maps/wikimap/mapspro/services/social/src/libs/feedback-actions/tasks_helpers.h>

using namespace std::string_literals;

namespace maps::wiki::socialsrv {

namespace mwsf = social::feedback;

namespace {

const auto SOURCE_SPRAV_GEOREF = "sprav-georef"s;

PostTaskResult createHypothesis(const std::string& externalReferenceId, const std::string& body)
{
    auto newTask = poiNewTaskFromProto(
        Globals::dbPools(), Globals::geosearchClient(), SOURCE_SPRAV_GEOREF, body);
    newTask.externalReferenceId = externalReferenceId;
    try {
        return postNewTask(Globals::dbPools(), newTask);
    } catch (const pqxx::integrity_constraint_violation& ex) {
        throw yacare::errors::Conflict() << "Duplicated id: " << externalReferenceId;
    }
}

mwsf::Task loadTask(const std::string& externalReferenceId, const std::string& token)
{
    auto socialTxn = Globals::dbPools().socialReadTxn(token);
    mwsf::GatewayRO gatewayRo(*socialTxn);
    auto task = gatewayRo.taskByExternalReferenceId(externalReferenceId);
    REQUIRE(task,
            yacare::errors::NotFound()
                << "Can not find task by id: " << externalReferenceId);
    return std::move(*task);
}

yacare::ThreadPool hypothesisThreadPool("hypothesisThreadPool", 4, 2048);

} // namespace

YCR_USE(hypothesisThreadPool) {

YCR_RESPOND_TO("POST /v1/hypothesis/add", externalReferenceId)
{
    try {
        auto result = createHypothesis(externalReferenceId, request.body());
        setSyncTokenHeader(response, result.token);
        response.setStatus(maps::http::Status::Created);
    } catch (const std::exception&) {
        catchAllErrors(response, "/v1/hypothesis/add");
    }
}

YCR_RESPOND_TO("GET /v1/hypothesis/get", externalReferenceId)
{
    try {
        auto task = loadTask(externalReferenceId, getSyncTokenFromHeader(request));
        response << makeHypothesisProto(task);
    } catch (const std::exception&) {
        catchAllErrors(response, "/v1/hypothesis/get");
    }
}

YCR_RESPOND_TO("GET /v1/hypothesis/result", externalReferenceId)
{
    try {
        auto task = loadTask(externalReferenceId, getSyncTokenFromHeader(request));
        if (task.resolved()) {
            response << makeHypothesisResultProto(Globals::dbPools(), task);
        } else {
            response.setStatus(maps::http::Status::Accepted);
        }
    } catch (const std::exception&) {
        catchAllErrors(response, "/v1/hypothesis/result");
    }
}

} // YCR_USE

} // namespace maps::wiki::socialsrv
