#pragma once

#include <maps/wikimap/mapspro/services/mrc/libs/db/tests/playground.h>

#include <library/cpp/testing/gtest/gtest.h>
#include <maps/libs/sql_chemistry/include/gateway.h>
#include <maps/libs/sql_chemistry/include/gateway_access.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/common.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/txn_id.h>

#include <string>
#include <utility>
#include <vector>

namespace maps::mrc::db::tests {

// The scheme is quite tiny, so it's acceptable create one every test case.
struct ObjectFixtureBase: public testing::Test {
    ObjectFixtureBase() {
        playground().postgres().executeSql(
            R"(
                DROP SCHEMA IF EXISTS dummy_object CASCADE;
                CREATE SCHEMA dummy_object;

                CREATE TABLE dummy_object.object(
                    id bigserial PRIMARY KEY,
                    txn_id bigserial NOT NULL,
                    value text
                );
            )"
        );
    }

    pgpool3::TransactionHandle txnHandle()
    {
        return playground().pool().masterWriteableTransaction();
    }
};

class Object {
public:
    Object(): id_(0), txnId_(0), value_() {}

    Object(std::string value): id_(0), txnId_(0), value_(std::move(value)) {}

    TId id() const { return id_; }

    const std::string& value() const { return value_; }

    TId txnId() const { return txnId_; }

    Object& setValue(std::string value) {
        value_ = std::move(value);
        return *this;
    }

private:
    friend class sql_chemistry::GatewayAccess<Object>;
    friend class TxnIdAccess<Object>;

    Object& setTxnId(TId txnId)
    {
        txnId_ = txnId;
        return *this;
    }

    template <typename T>
    static auto introspect(T& t) { return std::tie(t.id_, t.txnId_, t.value_); }

    TId id_;
    TId txnId_;
    std::string value_;
};

using Objects = std::vector<Object>;

namespace table {

using namespace sql_chemistry;

struct Object: Table<tests::Object> {
    static constexpr std::string_view name_{"dummy_object.object"sv};

    static constexpr BigSerialKey id{"id"sv, name_};
    static constexpr NumericColumn<TId> txnId{"txn_id"sv, name_};
    static constexpr StringColumn value{"value"sv, name_};

    static constexpr auto columns_() { return std::tie(id, txnId, value); }
};

} // namespace table

using Gateway = db::TxnIdGatewayBase<table::Object>;

} // namespace maps::mrc::db::tests
