#pragma once

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

#include <maps/libs/csv/include/csv.h>
#include <maps/libs/introspection/include/comparison.h>
#include <maps/libs/introspection/include/hashing.h>

#include <string>
#include <unordered_map>

namespace maps::wiki::stat_client {

/// Convenience class for reports preparation.
template<typename Dimensions, typename Measures, Scale reportScale>
class Report {
    static_assert(
        introspection::is_introspectable_v<Dimensions>,
        "Dimensions must be an introspectable type.");
    static_assert(
        std::is_default_constructible_v<Measures>,
        "Measures must be a default constructible type (used in underlying unordered_map::operator[])."
    );
public:
    Report(std::string name):
        name{std::move(name)}
    {}

    template <typename D>
    Measures&
    operator[](D&& dimensions) {
        return dimensionsToMeasures_[std::forward<D>(dimensions)];
    }

    void
    print(csv::OutputStream& os) const
    {
        Dimensions::printHeader(os);
        Measures::printHeader(os);
        for (const auto& [dimensions, measures]: dimensionsToMeasures_) {
            os << csv::endl;
            dimensions.print(os);
            measures.print(os);
        }
    }

    const std::string name;
    static const Scale scale = reportScale;

protected:
    std::unordered_map<Dimensions, Measures, introspection::Hasher> dimensionsToMeasures_;
};

} // namespace maps::wiki::stat_client
