#pragma once

#include <maps/libs/pgpool/include/pgpool3.h>
#include <pqxx/pqxx>

namespace maps::wiki::socialsrv {

typedef std::string DbToken;

class WriteContext
{
public:
    WriteContext(
            pgpool3::TransactionHandle&& coreTxn,
            pgpool3::TransactionHandle&& socialTxn);

    DbToken commit();

    pqxx::transaction_base& coreTxn() { return coreTxn_.get(); }
    pqxx::transaction_base& socialTxn() { return socialTxn_.get(); }

private:
    pgpool3::TransactionHandle coreTxn_;
    pgpool3::TransactionHandle socialTxn_;
};

class IDbPools
{
public:
    virtual ~IDbPools() = default;
    virtual pgpool3::TransactionHandle coreReadTxn(const DbToken& token = DbToken{}) = 0;
    virtual pgpool3::TransactionHandle socialReadTxn(const DbToken& token = DbToken{}) = 0;
    virtual WriteContext writeContext() = 0;
};

class IDbPoolsWithViewTrunk : public virtual IDbPools
{
public:
    virtual ~IDbPoolsWithViewTrunk() = default;
    virtual pgpool3::TransactionHandle viewTrunkTxn() = 0;
};

class DbPools : public virtual IDbPools
{
public:
    DbPools(pgpool3::Pool& core, pgpool3::Pool& social);

    WriteContext writeContext() override;

    pgpool3::TransactionHandle coreReadTxn(const DbToken& token = DbToken{}) override;

    pgpool3::TransactionHandle socialTxn();
    pgpool3::TransactionHandle socialReadTxn(const DbToken& token = DbToken{}) override;
    pgpool3::TransactionHandle socialRepeatableReadTxn();

private:
    pgpool3::Pool& core();
    pgpool3::Pool& social();

    pgpool3::Pool& core_;
    pgpool3::Pool& social_;
};

class DbPoolsWithViewTrunk : public DbPools, public IDbPoolsWithViewTrunk
{
public:
    DbPoolsWithViewTrunk(pgpool3::Pool& core, pgpool3::Pool& social, pgpool3::Pool& viewTrunk);

    pgpool3::TransactionHandle viewTrunkTxn() override;

private:
    pgpool3::Pool& viewTrunk();

    pgpool3::Pool& viewTrunk_;
};

} // namespace maps::wiki::socialsrv
