#include "jsonize_events.h"

#include <maps/libs/json/include/builder.h>
#include <maps/wikimap/mapspro/services/editor/src/serialize/json_common.h> // For editNotes serialization.
#include <maps/wikimap/mapspro/libs/gdpr/include/user.h>
#include <yandex/maps/wiki/common/date_time.h>
#include <maps/libs/geolib/include/serialization.h>
#include <maps/libs/geolib/include/conversion.h>

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

namespace maps::wiki::socialsrv {

namespace {
// clang-format off
const std::string STR_ACTION      = "action";
const std::string STR_BOUNDS      = "bounds";
const std::string STR_CATEGORY_ID = "categoryId";
const std::string STR_COMMIT      = "commit";
const std::string STR_DATA        = "data";
const std::string STR_DATE        = "date";
const std::string STR_EDIT_NOTES  = "editNotes";
const std::string STR_EVENTS      = "events";
const std::string STR_GEO_OBJECT  = "geoObject";
const std::string STR_ID          = "id";
const std::string STR_TITLE       = "title";
const std::string STR_UID         = "uid";
const std::string STR_POSITION    = "position";
// clang-format on
} // namespace

void jsonize(json::ObjectBuilder& builder, const EventData& eventData)
{
    const auto& event = eventData.event;
    const auto& commitData = event.commitData();

    ASSERT(commitData);
    ASSERT(event.primaryObjectData());

    auto authorUidStr = common::idToJson(gdpr::User(event.createdBy()).uid());

    builder[STR_ID] = common::idToJson(event.id());
    builder[STR_UID] = authorUidStr;
    builder[STR_DATE] = common::canonicalDateTimeString(event.createdAt(), common::WithTimeZone::Yes);
    builder[STR_ACTION] = event.action();

    builder[STR_POSITION] = geolib3::geojson(geolib3::convertMercatorToGeodetic(eventData.position));

    if (!event.bounds().empty()) {
        builder[STR_BOUNDS] = json::Verbatim(event.bounds());
    }

    builder[STR_DATA] << [&](json::ObjectBuilder dataBuilder) {
        dataBuilder[STR_COMMIT] << [&](json::ObjectBuilder commitBuilder) {
            commitBuilder[STR_ID] = common::idToJson(commitData->commitId());
            commitBuilder[STR_UID] = authorUidStr;
            commitBuilder[STR_DATE] = common::canonicalDateTimeString(event.createdAt(), common::WithTimeZone::Yes);
            commitBuilder[STR_ACTION] = commitData->action();

            const auto& editNotes = objectEditNotesTree(event.primaryObjectData()->editNotes());
            commitBuilder[STR_EDIT_NOTES] << [&](json::ObjectBuilder notesBuilder) {
                       putEditNotes(notesBuilder, editNotes.rootNotes);
                   };
            if (!commitData->bounds().empty()) {
                commitBuilder[STR_BOUNDS] = json::Verbatim(commitData->bounds());
            }
        };
        const auto& primaryData = *event.primaryObjectData();
        dataBuilder[STR_GEO_OBJECT] << [&](json::ObjectBuilder objectBuilder) {
                   objectBuilder[STR_ID] = common::idToJson(primaryData.id());
                   objectBuilder[STR_CATEGORY_ID] = primaryData.categoryId();
                   objectBuilder[STR_TITLE] = primaryData.screenLabel();
               };
    };
}

std::string toJson(const std::list<EventData>& eventsData)
{
    json::Builder builder;
    builder << [&](json::ObjectBuilder resultBuilder) {
        resultBuilder[STR_EVENTS] << [&](json::ArrayBuilder arrayBuilder) {
            for (const auto& eventData: eventsData) {
                arrayBuilder << [&](json::ObjectBuilder builder) {
                    jsonize(builder, eventData);
                };
            }
        };
    };
    return builder.str();
}

} // namespace maps::wiki::socialsrv
