#pragma once

#include "common.h"
#include "task_params.h"
#include "object.h"
#include "message_reporter.h"

#include <yandex/maps/wiki/revision/objectrevision.h>
#include <yandex/maps/wiki/revision/revisionsgateway.h>

namespace maps {
namespace wiki {
namespace importer {

enum class RelationType { Master, Slave };

class DbRelation;

class DbObject
{
public:
    DbObject() {}
    explicit DbObject(const revision::ObjectRevision& revision);

    revision::RevisionID revisionId() const { return revisionId_; }
    TObjectId dbId() const { return revisionId_.objectId(); }

    const std::string& categoryId() const { return categoryId_; }

    const StringMap& attributes() const { return attributesMap_; }
    void addAttribute(const std::string& id, const std::string& value);

    const std::vector<DbRelation>& slaves() const { return slaveRelations_; }
    const std::vector<DbRelation>& masters() const { return masterRelations_; }

    void addSlaveRelation(DbRelation&& relation) { slaveRelations_.push_back(std::move(relation)); }
    void addMasterRelation(DbRelation&& relation) { masterRelations_.push_back(std::move(relation)); }

protected:
    revision::RevisionID revisionId_;
    std::string categoryId_;
    StringMap attributesMap_;
    std::vector<DbRelation> slaveRelations_;
    std::vector<DbRelation> masterRelations_;
};

class DbRelation
{
public:
    DbRelation(
        RelationType relationType,
        const revision::ObjectRevision& revision);

    revision::RevisionID revisionId() const { return revisionId_; }
    TObjectId dbId() const { return revisionId_.objectId(); }

    const std::string& roleId() const { return roleId_; }

    TObjectId mainObjectId() const { return mainObjectId_; }
    TObjectId relatedObjectId() const { return relatedObjectId_; }

    const DbObject& relatedObject() const { return relatedObject_; }
    void setRelatedObject(DbObject&& object) { relatedObject_ = std::move(object); }

protected:
    revision::RevisionID revisionId_;
    std::string roleId_;
    TObjectId mainObjectId_;
    TObjectId relatedObjectId_;
    DbObject relatedObject_;
};

class RevisionsFacade
{
public:
    explicit RevisionsFacade(TaskParams& params);

    void loadObjectFromDb(
        const ObjectsCache& cache,
        MessageReporter& messageReporter);

    const DbObject& object(TObjectId objectId) const;

private:
    void loadRelations(
        RelationType relationType,
        MessageReporter& messageReporter);

    std::set<revision::DBID> loadDraftCommits();

    const EditorConfig& editorConfig_;

    pgpool3::TransactionHandle readTxn_;
    revision::RevisionsGateway gateway_;
    revision::Snapshot snapshot_;

    std::map<TObjectId, DbObject> objects_;
    ObjectIds objectIds_;
};

} // importer
} // wiki
} // maps
