#pragma once

#include "comment_impl.h"
#include "tables_columns.h"

#include <yandex/maps/wiki/social/comments_feed.h>
#include <yandex/maps/wiki/social/event_alert.h>
#include <yandex/maps/wiki/social/feed.h>
#include <yandex/maps/wiki/social/task.h>
#include <yandex/maps/wiki/social/feedback/task.h>

namespace maps::wiki::social {

class Factory
{
public:
    template <class Component, class ...Args>
    static Component component(Args&& ...args)
    {
        return Component(std::forward<Args>(args)...);
    }

    template <class Component, class ...Args>
    static Component componentCreate(Args&& ...args)
    {
        return Component::create(std::forward<Args>(args)...);
    }

    static Event commitEventWithComment(const pqxx::row& row)
    {
        Event event(row, NO_EVENT_EXTRA_DATA, Event::Kind::Commit);
        event.comment_ = Comment::loadFromJoined(row);
        return event;
    }

    static Event feedbackEventWithFeedback(const pqxx::row& row)
    {
        Event event(row, NO_EVENT_EXTRA_DATA, Event::Kind::Feedback);
        event.feedback_ = feedback::Task(row, FEEDBACK_TASK_FIELDS_PREFIX);
        return event;
    }

    static Task taskWithCommitEvent(const pqxx::row& row)
    {
        return Task(row, Event(row, NO_EVENT_EXTRA_DATA, Event::Kind::Commit));
    }

    static Task taskWithFeedbackEventAndFeedback(const pqxx::row& row)
    {
        return Task(row, feedbackEventWithFeedback(row));
    }

    static Task taskWithCommitEventAndComment(const pqxx::row& row)
    {
        return Task(row, commitEventWithComment(row));
    }

    static Comments comments(const pqxx::result& rows)
    {
        return convertRowsToObjects<Comment>(rows);
    }

    static EventAlerts eventAlerts(const pqxx::result& rows)
    {
        return convertRowsToObjects<EventAlert>(rows);
    }

private:
    template<typename Obj>
    static std::vector<Obj> convertRowsToObjects(const pqxx::result& rows)
    {
        std::vector<Obj> result;
        for (const auto& row : rows) {
            result.emplace_back(Obj(row));
        }
        return result;
    }
};

} // namespace maps::wiki::social
