#include "json_common.h"
#include <maps/wikimap/mapspro/services/editor/src/commit.h>
#include <maps/wikimap/mapspro/libs/gdpr/include/user.h>
#include <yandex/maps/wiki/common/json_helpers.h>
#include <yandex/maps/wiki/common/date_time.h>

namespace maps {
namespace wiki {

namespace {

const StringMap JSON_ACTION_NOTES = {
    {common::COMMIT_PROPKEY_GROUP_MOVED_DLON, STR_DELTA_LON},
    {common::COMMIT_PROPKEY_GROUP_MOVED_DLAT, STR_DELTA_LAT},
    {common::COMMIT_PROPKEY_GROUP_MOVED_OBJECTS_COUNT, STR_OBJECTS_COUNT},
    {common::COMMIT_PROPKEY_REVERT_REASON, STR_REVERT_REASON}
};
} // namespace

void
putTaskIds(json::ObjectBuilder& builder, const social::TaskIds& taskIds)
{
    putJsonIds(builder, STR_TASK_IDS, taskIds);
}

void
putActionNotes(json::ObjectBuilder& notesBuilder, const StringMap& actionNotes)
{
    for (const auto& actionNote : actionNotes) {
        auto it = JSON_ACTION_NOTES.find(actionNote.first);
        if (it != JSON_ACTION_NOTES.end())
            notesBuilder[it->second] = actionNote.second;
    }
}

void
putEditNotes(json::ObjectBuilder& notesBuilder, const std::vector<edit_notes::EditNotesTree::Node>& notesNodes)
{
    for (const auto& noteNode : notesNodes) {
        notesBuilder[noteNode.note] << [&](json::ObjectBuilder notesBuilderNext) {
            putEditNotes(notesBuilderNext, noteNode.subNotes);
        };
    }
}

void putCommitModel(
    json::ObjectBuilder& jsonCommitObject,
    const CommitModel& commitModel)
{
    const auto& commit = commitModel.commit();
    jsonCommitObject[STR_ID] = common::idToJson(commit.id());
    jsonCommitObject[STR_UID] = common::idToJson(gdpr::User(commit.createdBy()).uid());
    jsonCommitObject[STR_DATE] = common::canonicalDateTimeString(commit.createdAt(), common::WithTimeZone::Yes);
    jsonCommitObject[STR_ACTION] = commit.action();

    jsonCommitObject[STR_SOURCE_BRANCH_ID] = common::idToJson(sourceBranchId(commit));
    if (commit.stableBranchId()) {
        jsonCommitObject[STR_STABLE_BRANCH_ID] =
            common::idToJson(commit.stableBranchId());
    }

    auto revertedCommitIds = commit.revertedCommitIds();
    if (!revertedCommitIds.empty()) {
        putJsonIds(jsonCommitObject, STR_REVERTED_COMMIT_IDS, revertedCommitIds);
    }
    auto revertedDirectlyCommitIds = commit.revertedDirectlyCommitIds();
    if (!revertedDirectlyCommitIds.empty()) {
        putJsonIds(jsonCommitObject, STR_REVERTED_DIRECTLY_COMMIT_IDS, revertedDirectlyCommitIds);
    }
    auto revertingCommitIds = commit.revertingCommitIds();
    if (!revertingCommitIds.empty()) {
        putJsonIds(jsonCommitObject, STR_REVERTING_COMMIT_IDS, revertingCommitIds);
    }
    auto revertingDirectlyCommitId = commit.revertingDirectlyCommitId();
    if (revertingDirectlyCommitId) {
        jsonCommitObject[STR_REVERTING_DIRECTLY_COMMIT_ID] << common::idToJson(*revertingDirectlyCommitId);
    }

    auto actNotes = actionNotes(commit);
    if (!actNotes.empty()) {
        jsonCommitObject[STR_ACTION_NOTES] << [&](json::ObjectBuilder notesBuilder) {
            notesBuilder[commit.action()] << [&](json::ObjectBuilder actionNotesBuilder) {
                putActionNotes(actionNotesBuilder, actNotes);
            };
        };
    }

    if (commitModel.contextPrimaryObjectId()) {
        jsonCommitObject[STR_PRIMARY] = commitModel.primary();
        jsonCommitObject[STR_PRIMARY_OBJECT_ID] << common::idToJson(*commitModel.contextPrimaryObjectId());
    }

    if (commitModel.editNotesTree()) {
        jsonCommitObject[STR_EDIT_NOTES] << [&](json::ObjectBuilder notesBuilder) {
            putEditNotes(notesBuilder, commitModel.editNotesTree()->rootNotes);
        };
    }

    if (commitModel.state()) {
        jsonCommitObject[STR_STATE] = *commitModel.state();
    }
    if (commitModel.approveStatus()) {
        jsonCommitObject[STR_APPROVE_STATUS] = boost::lexical_cast<std::string>(
            *commitModel.approveStatus());
    }
    if (commitModel.last()) {
        jsonCommitObject[STR_LAST] = *commitModel.last();
    }
    if (commitModel.feedbackTaskId()) {
        jsonCommitObject[STR_FEEDBACK_TASK_ID] = common::idToJson(*commitModel.feedbackTaskId());
    }
    if (commitModel.isRevertible()) {
        jsonCommitObject[STR_REVERTIBLE] = *commitModel.isRevertible();
    }

}


} // namespace wiki
} // namespace maps
