#include "published_commits_notification_config.h"

#include <maps/libs/locale/include/find_helpers.h>
#include <maps/libs/locale/include/convert.h>

#include <array>
#include <algorithm>

namespace maps::wiki::notifications_dispatcher {

namespace {

const std::string NMAPS_URL_PATH = "/config/services/tasks/notifications-dispatcher/nmaps-url";
const std::string DEFAULT_LOCALE = "ru";

}  // namespace

PublishedCommitsNotificationConfig::PublishedCommitsNotificationConfig(
    const common::ExtendedXmlDoc& cfg,
    bell_client::NotificationType bellNotificationType,
    std::string bellActor,
    social::NotificationChannel sentNotificationChannel,
    social::NotificationType sentNotificationType
)
    : bellNotificationType_(bellNotificationType)
    , bellActor_(bellActor)
    , sentNotificationChannel_(sentNotificationChannel)
    , sentNotificationType_(sentNotificationType)
{
    auto nmapsUrlNode = cfg.node(NMAPS_URL_PATH);
    auto children = nmapsUrlNode.nodes("*");
    for (size_t i = 0; i < children.size(); ++i) {
        auto child = children[i];
        auto locale = locale::to<locale::Locale>(child.name());
        localizedNmapsUrl_[locale] = child.value<std::string>();
    }
}

bell_client::PushInfo PublishedCommitsNotificationConfig::makeBellPushInfo(
    const GroupedNotification& notification
) const {
    bell_client::PushInfo pushInfo(
        notification.uid,
        bellActor_,
        bellNotificationType_,
        makeBellMeta(notification)
    );

    pushInfo.groupKey = notification.groupKey;

    return pushInfo;
}

std::string localeBucket(const std::string& locale) {
    constexpr std::array<std::string_view, 6> EN_LOCALES{"en", "fr", "sr", "uz", "kk", "hy"};

    if (locale == "ru" || locale == "") {
        return "ru";
    } else if (locale == "tr") {
        return "tr";
    } else if (std::count(EN_LOCALES.begin(), EN_LOCALES.end(), locale)) {
        return "en";
    } else {
        return "ru";
    }
}

std::string PublishedCommitsNotificationConfig::nmapsUrl(const GroupedNotification& notification) const {
    auto localeString = notification.parameters["locale"].as<std::string>(DEFAULT_LOCALE);
    auto locale = locale::to<locale::Locale>(localeBucket(localeString));

    auto it = locale::findBest(localizedNmapsUrl_, locale);
    ASSERT(it != localizedNmapsUrl_.end());
    return it->second;
}

json::Value PublishedCommitsNotificationConfig::makeBellMeta(
    const GroupedNotification& notification
) const {
    auto commitsCount = notification.parameters["count"].as<size_t>();

    json::Builder meta;
    meta << [&](json::ObjectBuilder builder) {
        builder["count"] << [&](json::ObjectBuilder builder) {
            builder["type"] = "text";
            builder["text"] = std::to_string(commitsCount);
        };
        builder["action"] << [&](json::ObjectBuilder builder) {
            builder["type"] = "link";
            builder["link"] = nmapsUrl(notification) + "/#!/users/me/feeds/edits";
        };
    };

    return json::Value::fromString(meta.str());
}

social::SentNotification PublishedCommitsNotificationConfig::makeSentNotificationEntry(
    const GroupedNotification& notification,
    const std::string& channelNotificationId
) const {
    json::Builder argsBuilder;
    argsBuilder << [&](json::ObjectBuilder builder) {
        builder["notification_id"] = channelNotificationId;
        builder["commits_count"] = notification.parameters["count"].as<size_t>();
    };

    return social::SentNotification{
        0,
        notification.uid,
        sentNotificationChannel_,
        sentNotificationType_,
        json::Value::fromString(argsBuilder.str()),
        chrono::TimePoint::clock::now()
    };
}

std::string PublishedCommitsNotificationConfig::grouperNotificationType() const {
    return std::string(bell_client::toString(bellNotificationType_));
}

}  // namespace maps::wiki::notifications_dispatcher
