#include <maps/wikimap/mapspro/services/social_activity/src/api/globals.h>
#include <maps/wikimap/mapspro/services/social_activity/src/libs/yacare/helpers.h>
#include <maps/wikimap/mapspro/services/social_activity/src/libs/monitor/jsonize_events.h>
#include <maps/wikimap/mapspro/services/social_activity/src/libs/monitor/tile.h>

#include <maps/infra/yacare/include/params/tile.h>
#include <maps/libs/common/include/environment.h>
#include <maps/libs/log8/include/log8.h>

namespace maps::wiki::socialsrv {

namespace {

constexpr size_t LIMIT_MIN = 1;
constexpr size_t LIMIT_MAX = 1000;
constexpr auto THREADS = 16;
constexpr auto BACKLOG = 512;
constexpr auto THROTTLING_THRESHOLD = (THREADS * 3) / 4; // 75%

const std::string STR_ACTIVITY_MONITOR_PERMISSIONS =
    "mpro/social/activity-monitor";

yacare::ThreadPool monitorActivityThreadPool(
    "monitorActivityThreadPool", THREADS, BACKLOG);

class ActiveWorkersCounter {
public:
    ActiveWorkersCounter() { ++counter_; }
    ~ActiveWorkersCounter() { --counter_; }

    static bool needThrottling(const yacare::Request& request)
    {
        if (counter_ <= THROTTLING_THRESHOLD) {
            return false;
        }
        if (maps::common::getYandexEnvironment() != maps::common::Environment::Stable) {
            return false;
        }
        auto refresh = optionalQueryParam<bool>(request, "refresh");
        return !refresh || !*refresh; // no throttling if refresh=true
    }

private:
    static std::atomic<size_t> counter_;
};
std::atomic<size_t> ActiveWorkersCounter::counter_{0};

} // namespace

// clang-format off
YCR_RESPOND_TO("GET /monitor/tile", YCR_IN_POOL(monitorActivityThreadPool),
    uid, tile, limit = 1, token = "")
// clang-format on
{
    checkUid(uid);
    checkLimit(limit, LIMIT_MIN, LIMIT_MAX);

    ActiveWorkersCounter activeWorkersCounter;
    if (activeWorkersCounter.needThrottling(request)) {
        WARN() << "Throttling request: " << request;
        makeJsonResponse(response, toJson(std::list<EventData>()));
        return;
    }

    Globals::aclChecker().checkPermission(uid, STR_ACTIVITY_MONITOR_PERMISSIONS);

    const auto skipCreatedBy =
        optionalVectorQueryParam<std::string>(request, "skip-created-by");
    auto skippedUids =
        getIngnoredUids(skipCreatedBy, uid, Globals::userGroupsUidsCache());

    const auto events = getEventsForTile(
        Globals::dbPools(), Globals::editorConfig(),
        tile, limit, std::move(skippedUids), token);

    makeJsonResponse(response, toJson(events));
    INFO() << "ResultSize=" << events.size();
}

} // namespace maps::wiki::socialsrv
