#pragma once

#include <yandex/maps/wiki/social/comment.h>
#include <yandex/maps/wiki/social/common.h>
#include <yandex/maps/wiki/social/feedback/task.h>

#include <maps/libs/geolib/include/bounding_box.h>

#include <memory>
#include <optional>

namespace maps::wiki::social {

class Factory;

class CommitData
{
public:
    CommitData(
            TId branchId,
            TId commitId,
            std::string action,
            std::string bounds);

    TId branchId() const { return branchId_; }
    TId commitId() const { return commitId_; }
    const std::string& action() const { return action_; }
    const std::string& bounds() const { return bounds_; }
    const std::optional<geolib3::BoundingBox>& bbox() const { return bbox_; }

private:
    TId branchId_;
    TId commitId_;
    std::string action_;
    std::string bounds_;
    std::optional<geolib3::BoundingBox> bbox_;
};

class PrimaryObjectData
{
public:
    PrimaryObjectData(
            TId id,
            std::string categoryId,
            std::string screenLabel,
            std::string editNotes);

    TId id() const { return id_; }
    const std::string& categoryId() const { return categoryId_; }
    const std::string& screenLabel() const { return screenLabel_; }
    const std::string& editNotes() const { return editNotes_; }

private:
    TId id_;
    std::string categoryId_;
    std::string screenLabel_;
    std::string editNotes_;
};

struct EventExtraData {
    std::optional<FtTypeId> ftTypeId;
    std::optional<BusinessRubricId> businessRubricId;
};

extern const std::optional<EventExtraData> NO_EVENT_EXTRA_DATA;


class Event
{
public:
    TId id() const { return id_; }
    EventType type() const { return type_; }
    TUid createdBy() const { return createdBy_; }
    const std::string& createdAt() const { return createdAt_; }
    const std::string& action() const { return action_; }
    std::string bounds() const;

    const std::optional<CommitData>& commitData() const { return commitData_; }
    const std::optional<PrimaryObjectData>& primaryObjectData() const { return primaryObjectData_; }
    const std::optional<Comment>& comment() const { return comment_; }
    const std::optional<EventExtraData>& extraData() const { return extraData_; }
    const std::optional<feedback::Task>& feedback() const { return feedback_; }

    std::optional<std::string> getPrimaryObjectCategory() const;

    enum class Kind
    {
        Commit,
        Feedback
    };

private:
    friend class Factory;

    Event(
        const pqxx::row& row,
        std::optional<EventExtraData> extraData,
        Kind eventKind
    );

    /* Making here several things:
     * Create CommitEvent - inserting into social.commit_event table
     * Create extra data for commit - insering into social.event_extra_data
     * Creating events feed in AOIs - inserting into social.aoi_feed...
     */
    static Event create(
        pqxx::transaction_base& txn,
        EventType type,
        TUid uid,
        const CommitData& commitData,
        const std::optional<PrimaryObjectData>& primaryObjectData,
        const TIds& aoiIds,
        const std::optional<EventExtraData>& extraData
    );

    /*
     * Create FeedbackEvent - inserting into social.feedback_event
     * Creating events feed in AOIs - inserting into social.aoi_feed...
     */
    static Event create(
        pqxx::transaction_base& txn,
        TUid uid,
        const std::string& action,
        const feedback::Task& feedbackTask,
        const TIds& aoiIds);

    TId id_;
    EventType type_;
    TUid createdBy_;
    std::string createdAt_;
    std::string action_;
    std::optional<CommitData> commitData_;
    std::optional<PrimaryObjectData> primaryObjectData_;
    std::optional<Comment> comment_;
    std::optional<EventExtraData> extraData_;
    std::optional<feedback::Task> feedback_;
};

} // namespace maps::wiki::social
