#include <maps/wikimap/mapspro/libs/controller/include/asynctaskresult.h>
#include <maps/wikimap/mapspro/libs/controller/include/async_tasks_support.h>

#include "json_strings.h"

#include <yandex/maps/wiki/common/string_utils.h>
#include <maps/libs/pgpool/include/pgpool3.h>
#include <maps/libs/json/include/builder.h>

#include <sstream>

namespace maps::wiki::controller {

AsyncTaskResult::AsyncTaskResult(const taskutils::Token& token)
    : token_(token)
    , status_(token.expired() ? taskutils::TaskStatus::Expired : taskutils::TaskStatus::Unknown)
{}

AsyncTaskResult::AsyncTaskResult(
        const taskutils::Token& token,
        const taskutils::TaskResult& taskResult)
    : token_(token)
    , status_(taskutils::TaskStatus::Unknown)
{
    parse(taskResult);
}

void
AsyncTaskResult::load(const AsyncTasksSupport& asyncTasksSupport)
{
    if (token_.expired()) {
        status_ = taskutils::TaskStatus::Expired;
        return;
    }
    auto work = asyncTasksSupport.corePool().masterReadOnlyTransaction();
    parse(asyncTasksSupport.manager().load(*work, token_));
}

void
AsyncTaskResult::fail(const std::string& errorMsg)
{
    status_ = taskutils::TaskStatus::Failed;
    error_ = errorMsg;
}

void
AsyncTaskResult::parse(const taskutils::TaskResult& taskResult)
{
    status_ = taskResult.status();
    if (status_ == taskutils::TaskStatus::Done) {
        result_ = taskResult.result();
    }
    else if (status_ == taskutils::TaskStatus::Failed) {
        error_ = taskResult.errorMessage();
    }
}

std::string
AsyncTaskResult::toJson() const
{
    std::string errorJson;
    if (status() == taskutils::TaskStatus::Failed) {
        if (error().empty()) {
            json::Builder builder;
            builder << [&](json::ObjectBuilder objectBuilder) {
                objectBuilder[json_strings::STR_ERROR] << [&](json::ObjectBuilder errorBuilder) {
                    errorBuilder[json_strings::STR_STATUS] = common::escapeForJSON(json_strings::STR_INTERNAL_ERROR);
                    errorBuilder[json_strings::STR_MESSAGE] = "unknown error";
                };
            };
            errorJson = builder.str();
        } else {
            errorJson = error();
        }
    }

    json::Builder builder;
    builder << [&](json::ObjectBuilder objectBuilder) {
        objectBuilder[json_strings::STR_TASK] << [&](json::ObjectBuilder taskBuilder) {
            taskBuilder[json_strings::STR_ID] = token().str();
            taskBuilder[json_strings::STR_STATUS] = toString(status());
            if (status() == taskutils::TaskStatus::Done) {
                taskBuilder[json_strings::STR_RESULT] << maps::json::Verbatim(result());
            } else if (status() == taskutils::TaskStatus::Failed) {
                json::Value errorObject = json::Value::fromString(errorJson);
                taskBuilder[json_strings::STR_ERROR] << errorObject[json_strings::STR_ERROR];
            }
        };
    };
    return builder.str();
}

} // namespace maps::wiki::controller
