#pragma once

#include "../revision_meta/categories.h"
#include "../revision_meta/common.h"
#include "../revision_meta/snapshot.h"

#include <yandex/maps/wiki/common/pgpool3_helpers.h>
#include <yandex/maps/wiki/revision/branch.h>
#include <yandex/maps/wiki/revision/branch_manager.h>
#include <yandex/maps/wiki/revision/objectrevision.h>
#include <yandex/maps/wiki/revision/revisionsgateway.h>

#include <pqxx/pqxx>

namespace maps {
namespace wiki {
namespace contours {
namespace revision_meta {
namespace test {

const Categories& getCategories();

const revision::UserID TEST_UID = 13;
const std::string STR_DESCRIPTION = "description";
const revision::Attributes AD_FC_EL_PART_REL_ATTRS =
    {{"rel:master", "ad_fc"}, {"rel:slave", "ad_el"}, {"rel:role", "part"}};
const revision::Attributes AD_AD_FC_PART_REL_ATTRS =
    {{"rel:master", "ad"}, {"rel:slave", "ad_fc"}, {"rel:role", "part"}};
const revision::Attributes COMMIT_ATTRS =
    {{STR_DESCRIPTION, "revision_meta_test"}};

/// Filling database

class ObjectData {
public:
    ObjectData(revision::DBID newObjectId, const revision::Attributes& attrs);

    ObjectData(revision::RevisionID prevId, const revision::Attributes& attrs);

    ObjectData(revision::DBID newObjectId, const revision::Attributes& attrs, const revision::Wkb& geom);

    ObjectData(revision::RevisionID prevId, const revision::Wkb& geom);

    ObjectData(revision::DBID newObjectId, const revision::Attributes& attrs, const revision::RelationData& relationData);

    ObjectData(revision::RevisionID prevId, const revision::RelationData& relationData);

    /// delete existing or reincarnate deleted object
    ObjectData(revision::RevisionID prevId, bool deleted);

    TObjectId id() const { return data_.first.objectId(); }

    const revision::RevisionsGateway::NewRevisionData& data() const { return data_; }

private:
    revision::RevisionsGateway::NewRevisionData data_;
};

typedef std::vector<ObjectData> ObjectDataVector;

struct CommitData {
    TBranchId branchId;
    revision::UserID uid;
    revision::Attributes attrs;
    ObjectDataVector objectsData;
};

struct CommitsData {
    struct SingleCommitData {
        revision::Attributes attrs;
        std::vector<ObjectData> objectsData;
    };

    TBranchId branchId;
    revision::UserID uid;
    std::vector<SingleCommitData> commitsData;
};

revision::Commit
createCommit(const CommitData& data, Transaction& txn);

void
createCommits(const CommitsData& data, Transaction& txn);

void
fillDatabase(
    pgpool3::Pool& pool,
    TBranchId branchId,
    revision::UserID uid,
    const revision::Attributes& commitAttrs,
    const std::vector<ObjectDataVector>& commitsData);

/// Checking contents

void
checkObjectSlaves(
    revision_meta::Snapshot& snapshot,
    TObjectId objectId, const TObjectIdSet& expectedSlaveIds);

void
checkObjectMasters(
    revision_meta::Snapshot& snapshot,
    TObjectId objectId, const TObjectIdSet& expectedMasterIds);

} // namespace test
} // namespace revision_meta
} // namespace contours
} // namespace wiki
} // namespace maps
