#pragma once

#include <maps/libs/pgpool/include/pgpool3.h>
#include <yandex/maps/wiki/mds_dataset/types.h>
#include <yandex/maps/wiki/mds_dataset/dataset.h>
#include <yandex/maps/wiki/mds_dataset/exception.h>
#include <yandex/maps/mds/mds.h>

#include <memory>
#include <string>
#include <vector>

namespace maps {
namespace wiki {
namespace mds_dataset {

/**
 * @brief Gateway to create/delete datasets of specific type.
 * Dataset type is defined by the MetaData template parameter.
 * To read datasets, use \ref DatasetReader
 */
template <typename MetaData>
class DatasetWriter
{
public:
    typedef typename MetaData::FilterType FilterType;

    DatasetWriter(
        mds::Mds& mdsClient,
        pgpool3::Pool& pgPool);

    ~DatasetWriter();

    /// @brief Create new dataset
    Dataset<MetaData> createDataset(
            const MetaData& metadata,
            const std::vector<std::string>& filePaths,
            mds::Schema schema = mds::Schema::HTTP);

    /// @brief Remove dataset files for specified region from MDS, while keeping
    ////       the metadata and mark the dataset 'Deleted'
    void deleteDataset(const DatasetID& id, const Region& region);

    /// @brief Remove dataset files for default NO_REGION from MDS, while keeping
    ////       the metadata and mark the dataset 'Deleted'
    void deleteDataset(const DatasetID& id);

private:
    class Impl;
    std::unique_ptr<Impl> pimpl_;
};

/**
 * @brief Reader of datasets of specific type.
 * Dataset type is defined by the MetaData template parameter.
 * To create/delete datasets use \ref DatasetWriter
 */
template <typename MetaData>
class DatasetReader
{
public:
    typedef typename MetaData::FilterType FilterType;

    DatasetReader() = delete;

    /// @brief Get dataset by id and region
    static Dataset<MetaData> dataset(
        pqxx::transaction_base& txn,
        const DatasetID& id,
        const Region& region);

    /// @brief Get dataset with defult NO_REGION by id
    static Dataset<MetaData> dataset(
        pqxx::transaction_base& txn,
        const DatasetID& id);

    /// @brief Get all datasets
    /// @return datasets ordered by creation time starting from the newest
    static std::vector<Dataset<MetaData>> datasets(
        pqxx::transaction_base& txn);

    /// @brief Get datasets by filter
    /// @return datasets ordered by creation time starting from the newest
    static std::vector<Dataset<MetaData>> datasets(
        pqxx::transaction_base& txn,
        const FilterType& filter);

    /// @brief Get datasets by filter with limit and offset
    /// @return datasets ordered by creation time starting from the newest
    static std::vector<Dataset<MetaData>> datasets(
        pqxx::transaction_base& txn,
        const FilterType& filter,
        size_t limit,
        size_t offset = 0);

private:
    class Impl;
};

} // mds_dataset
} // wiki
} // maps
