#include "post_to_social.h"
#include "magic_strings.h"
#include <maps/wikimap/mapspro/services/tasks_feedback/src/sprav_pedestrian_feedback/lib/social.h>
#include <maps/wikimap/mapspro/services/tasks_feedback/src/sprav_pedestrian_feedback/lib/social_constants.h>

#include <maps/libs/http/include/http.h>
#include <maps/wikimap/mapspro/libs/http/http_utils.h>
#include <maps/libs/geolib/include/serialization.h>
#include <maps/libs/json/include/builder.h>

#include <chrono>

namespace maps::wiki::sprav_feedback {

namespace {

const std::string FEEDBACK_HANDLE = "/feedback/tasks";

std::string generateDescription(const SpravFeedback& fb)
{
    std::string descr;

    if (fb.address) {
        descr += "Адрес:\n\"" + *fb.address + "\"\n\n";
    }

    if (fb.comment) {
        descr += "Комментарий:\n\"" + *fb.comment + "\"\n\n";
    }

    if (!fb.photoUrls.empty()) {
        descr += "Фото:\n";
        int count = 1;
        for (const auto& url : fb.photoUrls) {
            descr += std::to_string(count) + ") " + url + "\n";
            count++;
        }
    }

    return descr;
}

std::string nmapsSourceFromSpravType(const std::string& spravFeedbackType)
{
    if (spravFeedbackType == CHANGE_IN_BASE) {
        return "sprav-change-in-base";
    } else if (spravFeedbackType == CHANGE_NOT_IN_BASE) {
        return "sprav-change-not-in-base";
    } else {
        return "sprav";
    }
}

std::string postRequestBody(const SpravFeedback& fb)
{
    json::Builder bodyBuilder;
    bodyBuilder << [&](json::ObjectBuilder bodyBuilder) {
        bodyBuilder[jf::TYPE] = TYPE_ADDRESS;
        bodyBuilder[jf::HIDDEN] = true;
        bodyBuilder[jf::SOURCE] = nmapsSourceFromSpravType(fb.spravFeedbackType);
        bodyBuilder[jf::WORKFLOW] = WORKFLOW_FEEDBACK;
        bodyBuilder[jf::POSITION] = geolib3::geojson(fb.pointGeo);
        bodyBuilder[jf::DESCR] = generateDescription(fb);

        bodyBuilder[jf::USER_ATTRS] = [&](json::ObjectBuilder userAttrsBuilder) {
            userAttrsBuilder["spravTaskId"] = fb.spravTaskId;
            userAttrsBuilder["submitTimeUnixMs"] = fb.submitTimeUnixMs;
            userAttrsBuilder["createdAtTimeUnixMs"] = fb.createdAtTimeUnixMs;
            userAttrsBuilder["spravUserId"] = fb.spravUserId;
        };
    };

    return bodyBuilder.str();
}

} // unnamed namespace

void publishFeedback(const SpravFeedback& fb, const std::string& socialUrl)
{
    http::URL socialHttpUrl(socialUrl);
    socialHttpUrl.setPath(FEEDBACK_HANDLE);

    const size_t maxAttempts = 6;
    const std::chrono::seconds initialTimeout{1};
    const double timeoutBackoff = 2;

    auto retryPolicy = maps::common::RetryPolicy()
        .setTryNumber(maxAttempts)
        .setInitialCooldown(initialTimeout)
        .setCooldownBackoff(timeoutBackoff);

    http::Client httpClient;
    auto [response, status] = httpClient.post(
        socialHttpUrl,
        socialBackofficeHttpHeaders(),
        postRequestBody(fb),
        retryPolicy);

    REQUIRE(status == http_status::OK,
        "Unable to post feedback; Response status: " << status);
}

} // namespace maps::wiki::sprav_feedback
