#pragma once

#include <maps/wikimap/mapspro/services/tasks_realtime/src/user_edits_metrics/lib/metrics.h>
#include <maps/wikimap/mapspro/services/tasks_realtime/src/user_edits_metrics/lib/util.h>
#include <maps/wikimap/mapspro/services/tasks_realtime/src/user_edits_metrics/lib/stat_utils/report_data_uploader.h>

#include <maps/wikimap/mapspro/libs/stat_client/include/report.h>

#include <maps/libs/chrono/include/days.h>
#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/introspection/include/comparison.h>
#include <maps/libs/introspection/include/stream_output.h>

#include <chrono>
#include <optional>
#include <string>

namespace maps::wiki::user_edits_metrics {

using introspection::operator==;
using introspection::operator<<;


class DeploymentSlaDimensions {
public:
    DeploymentSlaDimensions(
        chrono::TimePoint fielddate,
        Days days,
        std::string region,
        size_t userType,
        unsigned char percentile,
        size_t window,
        size_t budget,
        bool inTrunk
    );

    auto introspect() const {
        return std::make_tuple(
            maps::chrono::formatIsoDateTime(fielddate_),
            days_,
            region_,
            userType_,
            percentile_,
            window_,
            budget_,
            inTrunk_
        );
    }

    static void printHeader(csv::OutputStream& os);
    void print(csv::OutputStream& os) const;

    std::map<std::string, std::string> keyValues(pqxx::transaction_base& txn) const;

private:
    std::chrono::time_point<std::chrono::system_clock, chrono::Days> fielddate_;
    Days days_;
    std::string region_;
    size_t userType_;
    unsigned char percentile_;
    size_t window_;
    size_t budget_;
    bool inTrunk_;
};


struct DeploymentSlaMeasures {
    std::optional<std::chrono::seconds> brokenSla;
    std::optional<std::chrono::seconds> realSla;
    std::optional<std::chrono::seconds> bicycleGraphBrokenSla;
    std::optional<std::chrono::seconds> bicycleGraphRealSla;
    std::optional<std::chrono::seconds> camerasBrokenSla;
    std::optional<std::chrono::seconds> camerasRealSla;
    std::optional<std::chrono::seconds> carparksBrokenSla;
    std::optional<std::chrono::seconds> carparksRealSla;
    std::optional<std::chrono::seconds> geocoderBrokenSla;
    std::optional<std::chrono::seconds> geocoderRealSla;
    std::optional<std::chrono::seconds> graphBrokenSla;
    std::optional<std::chrono::seconds> graphRealSla;
    std::optional<std::chrono::seconds> mtrExportBrokenSla;
    std::optional<std::chrono::seconds> mtrExportRealSla;
    std::optional<std::chrono::seconds> pedestrianGraphBrokenSla;
    std::optional<std::chrono::seconds> pedestrianGraphRealSla;
    std::optional<std::chrono::seconds> rendererBrokenSla;
    std::optional<std::chrono::seconds> rendererRealSla;

    static void printHeader(csv::OutputStream& os);
    void print(csv::OutputStream& os) const;
    bool realSlaFilled() const;

    std::map<std::string, std::string> keyValues() const;
};


class DeploymentSlaReport:
    public stat_client::Report<
        DeploymentSlaDimensions,
        DeploymentSlaMeasures,
        stat_client::Scale::Daily
    >,
    public ReportDataUploader
{
public:
    DeploymentSlaReport();
    void add(const MetricVec& metrics, size_t window, size_t budget);
    void removeIncompleteDimensions();

    void upload(pqxx::transaction_base& txn) const;
};

} // namespace maps::wiki::user_edits_metrics
