#include "common.h"

#include <maps/libs/common/include/exception.h>
#include <yandex/maps/wiki/common/pg_utils.h>
#include <maps/libs/enum_io/include/enum_io.h>
#include <maps/libs/locale/include/convert.h>
#include <maps/libs/locale/include/find_helpers.h>

#include <boost/lexical_cast.hpp>

#include <sstream>
#include <vector>

namespace maps::wiki::releases_notification {

namespace {

constexpr enum_io::Representations<ReleaseType>
RELEASE_TYPE_STRINGS {
    {ReleaseType::Vec, "vec"},
    {ReleaseType::Sat, "sat"},
    {ReleaseType::Event, "event"},
    {ReleaseType::News, "news"},
    {ReleaseType::Survey, "survey"}
};

constexpr enum_io::Representations<Mode>
MODE_STRINGS {
    {Mode::Test, "test"},
    {Mode::Dry, "dry"},
    {Mode::Real, "real"}
};

const std::string CONFIG_PREFIX = "/config/services/tasks/releases-notification";

} // namespace

DEFINE_ENUM_IO(ReleaseType, RELEASE_TYPE_STRINGS);

DEFINE_ENUM_IO(Mode, MODE_STRINGS);


TaskParams::TaskParams(pqxx::transaction_base& txnCore, revision::DBID dbTaskId)
    : dbTaskId_(dbTaskId)
{
    std::ostringstream query;
    query << " SELECT blog_url, mode, release_type, test_emails"
          << " FROM service.releases_notification_task"
          << " WHERE id = " << dbTaskId_;
    auto result = txnCore.exec(query.str());
    REQUIRE(not result.empty(), "Task hasn't been prepared yet");

    blogUrl_ = result[0]["blog_url"].as<std::string>();
    mode_ = enum_io::fromString<Mode>(result[0]["mode"].as<std::string>());
    releaseType_ = enum_io::fromString<ReleaseType>(
        result[0]["release_type"].as<std::string>());
    testEmails_ = common::parseSqlArray(result[0]["test_emails"].as<std::string>());
}

TaskParams::TaskParams(
    std::string blogUrl,
    Mode mode,
    ReleaseType releaseType,
    revision::DBID dbTaskId,
    std::vector<Email> testEmails
)
    : blogUrl_(std::move(blogUrl))
    , mode_(mode)
    , releaseType_(releaseType)
    , dbTaskId_(dbTaskId)
    , testEmails_(std::move(testEmails))
{}

namespace {

const size_t MAX_REQUESTS_RETRY_DEFAULT = 10;
const std::chrono::milliseconds INITIAL_TIMEOUT_RETRY_DEFAULT = std::chrono::seconds{1};
const double TIMEOUT_BACKOFF_RETRY_DEFAULT = 2.0;

} // namespace

maps::common::RetryPolicy defaultRetryPolicy()
{
    return maps::common::RetryPolicy()
        .setTryNumber(MAX_REQUESTS_RETRY_DEFAULT)
        .setInitialCooldown(INITIAL_TIMEOUT_RETRY_DEFAULT)
        .setCooldownBackoff(TIMEOUT_BACKOFF_RETRY_DEFAULT);
}

std::string getBestLocalizedString(
    const sender::LocalizedString& localizedString,
    const locale::Locale& locale)
{
    const auto& langToStr = localizedString.getAllLangs();
    const auto bestIt = locale::findBest(
        langToStr.begin(),
        langToStr.end(),
        locale,
        [](const auto& langString){
            return locale::to<locale::Locale>(langString.first);
        }
    );
    ASSERT(bestIt != langToStr.end());
    return bestIt->second;
}

} // namespace maps::wiki::releases_notification

