#include "publish.h"
#include "publish_commit.h"
#include "publish_feedback.h"
#include "process_entrance.h"
#include "print_info.h"

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

#include <util/generic/typetraits.h>

#include <algorithm>
#include <cctype>
#include <cmath>
#include <variant>

namespace maps::wiki::sprav_feedback {

namespace {

revision::DBID publishCommit(
    const std::string& editorUrl,
    const CommitPublishData& commitData)
{
    return std::visit([&](auto&& arg) {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, geolib3::Point2>) {
            const geolib3::Point2& entrancePoint = arg;
            return createEntrance(editorUrl, entrancePoint,
                commitData.entranceName);
        } else if constexpr (std::is_same_v<T, revision::DBID>) {
            revision::DBID entranceId = arg;
            return renameEntrance(editorUrl, entranceId, commitData.entranceName);
        } else {
            static_assert(TDependentFalse<T>, "non-exhaustive visitor!");
        }
    }, commitData.entrance);
}

} // unnamed namespace

void publishEntrances(
    pqxx::transaction_base& coreTxn,
    pqxx::transaction_base& viewTrunkTxn,
    const EntrancesData& entrancesData,
    const std::string& socialUrl,
    const std::string& editorUrl)
{
    if (entrancesData.state == EntrancesData::State::Entry) {
        if (entrancesData.entrances.empty()) {
            auto fbId = publishFeedback(entrancesData.pointGeo, entrancesData,
                socialUrl, FeedbackReason::EntryButNoData);
            INFO() << "Unexpected empty entrances. Feedback " << fbId << " published.";
        } else {
            if (entrancesData.comment && !entrancesData.comment->empty()) {
                auto fbId = publishFeedback(entrancesData.pointGeo, entrancesData,
                    socialUrl, FeedbackReason::CommentForEntry);
                INFO() << "Feedback " << fbId << " published.";
            }
            for (const auto& entrance : entrancesData.entrances) {
                INFO() << "Processing particular entrance with name '"
                    << entrance.name << "'";
                auto publishData = processEntrance(coreTxn, viewTrunkTxn, entrance);

                std::visit([&](auto&& arg) {
                    using T = std::decay_t<decltype(arg)>;
                    if constexpr (std::is_same_v<T, FeedbackPublishData>) {
                        FeedbackPublishData& feedbackData = arg;
                        auto fbId = publishFeedback(feedbackData.entrance.pointGeo, entrancesData, socialUrl,
                            feedbackData.reason, feedbackData.entrance.name);
                        INFO() << "Feedback Id: " << fbId;
                    } else if constexpr (std::is_same_v<T, CommitPublishData>) {
                        CommitPublishData& commitData = arg;
                        auto objectId = publishCommit(editorUrl, commitData);
                        printCommitInfo(objectId);
                    } else if constexpr (std::is_same_v<T, SkipReason>) {
                        // no code
                    } else {
                        static_assert(TDependentFalse<T>, "non-exhaustive visitor!");
                    }
                }, publishData);

                std::visit(
                    [](auto&& data){ printLog(data); }
                    , publishData);
            }
        }
    } else if (entrancesData.state == EntrancesData::State::NoEntry) {
        if (entrancesData.entrances.empty()) {
            if (entrancesData.comment && !entrancesData.comment->empty()) {
                auto fbId = publishFeedback(entrancesData.pointGeo, entrancesData,
                    socialUrl, FeedbackReason::CommentForNoEntry);
                INFO() << "Feedback " << fbId << " published because of non empty comment.";
            }
            INFO() << "No entrances found by pedestrian. It is ok.";
        } else {
            auto fbId = publishFeedback(entrancesData.pointGeo, entrancesData,
                socialUrl, FeedbackReason::NoEntryButData);
            INFO() << "Unexpected NON-empty entrances in 'no-entry' feedback."
                << " Feedback " << fbId << " published.";
        }
    } else {
        INFO() << "State = never-done. No action needed.";
    }
}

} // namespace maps::wiki::sprav_feedback
