#include "magic_strings.h"

#include <yandex/maps/wiki/diffalert/storage/issue_creator.h>
#include <yandex/maps/wiki/common/passport_to_staff.h>
#include <yandex/maps/wiki/common/secrets.h>

#include <maps/libs/log8/include/log8.h>

#include <boost/format.hpp>

namespace maps::wiki::diffalert {

namespace {

const std::string ST_QUEUE_KEY = "MAPSERRORS";

const boost::format DESCRIPTION_FORMAT(
R"(Номер ветки: %1%
Описание ошибки: %2%
Сообщил об ошибке: %3%
Ссылка на проблемный объект: %4%
Ссылка на сообщение об ошибке: %5%)");

} // namespace

IssueCreator::IssueCreator(std::string baseUrl)
    : stGateway_(st::Configuration(
            std::move(baseUrl),
            common::secrets::tokenByKey(
                common::secrets::Key::RobotWikimapStToken)))
{
}

IssueCreator::IssueCreator(std::string baseUrl, std::string oAuthToken)
    : stGateway_(st::Configuration(
            std::move(baseUrl),
            std::move(oAuthToken)))
{
}

std::string IssueCreator::getOrCreateIssue(
    pqxx::transaction_base& txn,
    const StoredMessage& message,
    TId branchId,
    const std::string& reporterLogin,
    const std::string& categoryGroup,
    const std::string& pageUrl)
{
    auto result = txn.exec(
        "SELECT issue_key "
        "FROM diffalert.startrek_issue "
        "WHERE message_id=" + std::to_string(message.id()));
    if (!result.empty()) {
        return result[0][0].as<std::string>();
    }

    std::string key;
    try {
        key = createIssue(message, branchId, reporterLogin, categoryGroup, pageUrl);
    } catch (const st::ConflictError& e) {
        INFO() << "Conflict error. Try to find issue";
        key = findIssue(message.id());
    }
    REQUIRE(!key.empty(), "Key is empty");

    txn.exec(
        "INSERT INTO diffalert.startrek_issue "
        "VALUES (" + std::to_string(message.id()) + "," + txn.quote(key) + ")");

    return key;
}

std::string IssueCreator::createIssue(
    const StoredMessage& message,
    TId branchId,
    const std::string& reporterLogin,
    const std::string& categoryGroup,
    const std::string& pageUrl)
{
    st::IssuePatch issuePatch;
    issuePatch.summary().set("Ошибка в релизной ветке #" + std::to_string(branchId));

    auto description = (boost::format(DESCRIPTION_FORMAT)
        % branchId
        % message.description()
        % reporterLogin
        % ("https://n.maps.yandex.ru/#!/objects/" + std::to_string(message.objectId()))
        % pageUrl).str();

    issuePatch.description().set(description);

    const auto staffLogin = common::getStaffLoginByPassportLogin(reporterLogin);
    if (!staffLogin.empty()) {
        issuePatch.createdBy().set(staffLogin);
    }

    auto uniqueTag = "diffalert_" + std::to_string(message.id());
    auto objectTag = "object_" + std::to_string(message.objectId());
    auto priorityTag = "diffalert_priority_" + std::to_string(message.priority().major);
    auto loginTag = "login_" + reporterLogin;

    issuePatch.tags().set({categoryGroup, priorityTag, uniqueTag, objectTag, loginTag});

    auto issue = stGateway_.createIssue(ST_QUEUE_KEY, issuePatch, uniqueTag);

    INFO() << "Issue created " << issue.key();

    return issue.key();
}

std::string IssueCreator::findIssue(StoredMessageId messageId)
{
    auto unique = "diffalert_" + std::to_string(messageId);

    auto query = "Tags: " + unique;

    auto collection = stGateway_.loadIssues(query);
    REQUIRE(collection.begin() != collection.end(),
        "Failed to find issue for the diffalert message " << messageId);
    const auto& issue = *collection.begin();

    INFO() << "Issue found " << issue.key();

    return issue.key();
}

} // namespace maps::wiki::diffalert
