#pragma once

#include <maps/libs/concurrent/include/background_thread.h>
#include <maps/libs/pgpool/include/pgpool3.h>

#include <yandex/maps/wiki/common/pgpool3_helpers.h>

#include <atomic>
#include <chrono>
#include <memory>

namespace maps::wiki::maintenance {

using MetricValue = int64_t;

struct SqlMetricStrategy {
    SqlMetricStrategy() = default;
    virtual ~SqlMetricStrategy() = default;

    virtual MetricValue getValue(
        pqxx::transaction_base& txn, const std::string& query) const = 0;
};

class SqlMetric {
public:
    SqlMetric(
        pgpool3::Pool& pool,
        std::string workerName,
        std::chrono::seconds ttl,
        std::string query,
        std::shared_ptr<SqlMetricStrategy> strategy
    );

    MetricValue getValue();

private:
    void update();

    pgpool3::Pool& pool_;
    std::string workerName_;
    std::atomic<MetricValue> lastValue_{0};
    const std::string query_;
    std::shared_ptr<SqlMetricStrategy> strategy_;
    concurrent::BackgroundThread worker_;
};


class SqlMetricStrategyQueryTime : public SqlMetricStrategy {
public:
    SqlMetricStrategyQueryTime() = default;

    virtual MetricValue getValue(
        pqxx::transaction_base& txn, const std::string& query) const override;
};

class SqlMetricStrategyQueryValue : public SqlMetricStrategy {
public:
    SqlMetricStrategyQueryValue() = default;

    virtual MetricValue getValue(
        pqxx::transaction_base& txn, const std::string& query) const override;
};

} // namespace maps::wiki::maintenance
