#include "globals.h"

#include <maps/wikimap/mapspro/libs/sqs_client/include/configuration.h>
#include <maps/wikimap/mapspro/libs/sqs_client/include/client.h>

#include <yandex/maps/wiki/common/extended_xml_doc.h>
#include <yandex/maps/wiki/common/pgpool3_helpers.h>

#include <yandex/maps/mds/mds.h>
#include <maps/libs/common/include/retry.h>
#include <maps/libs/json/include/value.h>
#include <maps/libs/log8/include/log8.h>

#include <maps/libs/auth/include/tvm.h>
#include <library/cpp/tvmauth/client/facade.h>

#include <chrono>
#include <memory>

namespace maps::wiki::socialsrv {

namespace {

const std::string CORE_DB_ID = "core";
const std::string SOCIAL_DB_ID = "social";
const std::string VIEW_TRUNK_DB_ID = "view-trunk";
const std::string POOL_ID = "social";

const std::string CONFIG_PATH_RATELIMITER = "/config/common/rate-limiter";
const std::string CONFIG_PATH_MDS = "/config/common/mds";
const std::string CONFIG_PATH_MRC_BROWSER_PRO = "/config/services/mrc-browser-pro/url";
const std::string CONFIG_PATH_TASKUTILS = "/config/services/social/tasks/";
const std::string CONFIG_FEEDBACK_REVIEW_SETTINGS = "/config/services/social/feedback-review";
const std::string FB_REVIEW_TRANSLATIONS_RESOURCE_ID = "fb-review-translations";
const auto TVM_SOCIAL_ALIAS = "nmaps-social";
const size_t RETRY_COUNT = 3;

const size_t ACL_CACHE_MAX_SIZE = 10 * 1000;
constexpr std::chrono::seconds ACL_CACHE_EXPIRATION_PERIOD(300);

const size_t FB_PRESET_CACHE_MAX_SIZE = 10 * 1000;
constexpr std::chrono::seconds FB_PRESET_CACHE_EXPIRATION_PERIOD(60);

struct GlobalData
{
    explicit GlobalData(const common::ExtendedXmlDoc& config);
    ~GlobalData();
    sqs::Configuration sqsConfig;
    Aws::SQS::SQSClient sqsClient;

    common::PoolHolder corePoolHolder;
    common::PoolHolder socialPoolHolder;
    common::PoolHolder viewTrunkPoolHolder;
    DbPoolsWithViewTrunk dbpools;

    acl_utils::CachingAclChecker aclChecker;
    acl_utils::FeedbackPresetCheckerImpl fbPresetChecker;
    acl_utils::FeedbackChecker feedbackChecker;

    assessment::RateLimiter assessmentRateLimiter;
    social::RateLimiter socialRateLimiter;

    json::Value fbReviewTranslations;
    NTvmAuth::TTvmClient tvmClient;
    mds::Configuration mdsConfiguration;
    std::string mrcBrowserProUrl;
    controller::AsyncTasksSupport asyncTasksSupport;
    bool feedbackReviewNewTasksOnly = true;
};

GlobalData::GlobalData(const common::ExtendedXmlDoc& config)
    : sqsConfig(config)
    , sqsClient(sqs::createSqsClient(sqsConfig))

    , corePoolHolder(config, CORE_DB_ID, POOL_ID)
    , socialPoolHolder(config, SOCIAL_DB_ID, POOL_ID)
    , viewTrunkPoolHolder(config, VIEW_TRUNK_DB_ID, POOL_ID)
    , dbpools(corePoolHolder.pool(),
        socialPoolHolder.pool(),
        viewTrunkPoolHolder.pool())

    , aclChecker(corePoolHolder.pool(),
        ACL_CACHE_MAX_SIZE,
        ACL_CACHE_EXPIRATION_PERIOD)
    , fbPresetChecker(
        corePoolHolder.pool(),
        socialPoolHolder.pool(),
        FB_PRESET_CACHE_MAX_SIZE,
        FB_PRESET_CACHE_EXPIRATION_PERIOD)
    , feedbackChecker(aclChecker, fbPresetChecker)

    , assessmentRateLimiter(config.node(CONFIG_PATH_RATELIMITER, true))
    , socialRateLimiter(config.node(CONFIG_PATH_RATELIMITER, true))

    , fbReviewTranslations(json::Value::fromResource(FB_REVIEW_TRANSLATIONS_RESOURCE_ID))
    , tvmClient(auth::TvmtoolSettings().selectClientAlias(TVM_SOCIAL_ALIAS).makeTvmClient())
    , mdsConfiguration(
        config.getAttr<std::string>(CONFIG_PATH_MDS, "host"),
        config.getAttr<std::string>(CONFIG_PATH_MDS, "namespace-name"),
        config.getAttr<std::string>(CONFIG_PATH_MDS, "auth-header"))
    , mrcBrowserProUrl(config.get<std::string>(CONFIG_PATH_MRC_BROWSER_PRO))
    , asyncTasksSupport(
        corePoolHolder.pool(),
        config,
        CONFIG_PATH_TASKUTILS)
    , feedbackReviewNewTasksOnly(
        config.getAttr<bool>(CONFIG_FEEDBACK_REVIEW_SETTINGS, "new-tasks-only"))
{
    mdsConfiguration
        .setMaxRequestAttempts(RETRY_COUNT)
        .setRetryInitialTimeout(std::chrono::seconds(1))
        .setRetryTimeoutBackoff(2);
    INFO() << "feedbackReviewNewTasksOnly: " << feedbackReviewNewTasksOnly;
}

GlobalData::~GlobalData()
{
    asyncTasksSupport.shutdown();
    asyncTasksSupport.terminateTasks();
}

std::unique_ptr<GlobalData> g_globalData;

} // namespace

GlobalsScope::GlobalsScope(const common::ExtendedXmlDoc& config)
{
    g_globalData = std::make_unique<GlobalData>(config);
}

GlobalsScope::~GlobalsScope()
{
    g_globalData.reset();
}

const sqs::Configuration& Globals::sqsConfig()
{
    ASSERT(g_globalData);
    return g_globalData->sqsConfig;
}

const Aws::SQS::SQSClient& Globals::sqsClient()
{
    ASSERT(g_globalData);
    return g_globalData->sqsClient;
}

DbPoolsWithViewTrunk& Globals::dbPools()
{
    ASSERT(g_globalData);
    return g_globalData->dbpools;
}

acl_utils::CachingAclChecker& Globals::aclChecker()
{
    ASSERT(g_globalData);
    return g_globalData->aclChecker;
}

const acl_utils::FeedbackChecker& Globals::feedbackChecker()
{
    ASSERT(g_globalData);
    return g_globalData->feedbackChecker;
}

const assessment::RateLimiter& Globals::assessmentRateLimiter()
{
    ASSERT(g_globalData);
    return g_globalData->assessmentRateLimiter;
}

const social::RateLimiter& Globals::socialRateLimiter()
{
    ASSERT(g_globalData);
    return g_globalData->socialRateLimiter;
}

const json::Value& Globals::fbReviewTranslations()
{
    ASSERT(g_globalData);
    return g_globalData->fbReviewTranslations;
}

const NTvmAuth::TTvmClient& Globals::tvmClient()
{
    ASSERT(g_globalData);
    return g_globalData->tvmClient;
}

const mds::Configuration& Globals::mdsConfiguration()
{
    ASSERT(g_globalData);
    return g_globalData->mdsConfiguration;
}

const std::string& Globals::mrcBrowserProUrl()
{
    ASSERT(g_globalData);
    return g_globalData->mrcBrowserProUrl;
}

const controller::AsyncTasksSupport&
Globals::asyncTasksSupport()
{
    ASSERT(g_globalData);
    return g_globalData->asyncTasksSupport;
}

bool Globals::feedbackReviewNewTasksOnly()
{
    ASSERT(g_globalData);
    return g_globalData->feedbackReviewNewTasksOnly;
}

} // namespace maps::wiki::socialsrv
