/*
 * SPDX-FileCopyrightText: 2025 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */
#ifndef TANGO_INTERNAL_TELEMETRY_TOPICSAMPLER_H
#define TANGO_INTERNAL_TELEMETRY_TOPICSAMPLER_H

#include <tango/common/telemetry/Configuration.h>
#include <tango/common/telemetry/consts.h>

#include <opentelemetry/common/key_value_iterable.h>
#include <opentelemetry/sdk/trace/sampler.h>

namespace Tango::telemetry
{

//-----------------------------------------------------------------------------------------
// Sampler to accept/reject spans based upon the topics set in the configuration
//-----------------------------------------------------------------------------------------
class TopicSampler : public opentelemetry::sdk::trace::Sampler
{
  public:
    TopicSampler(const Configuration &config) :
        cfg{config}
    {
    }

    opentelemetry::sdk::trace::SamplingResult
        ShouldSample([[maybe_unused]] const opentelemetry::trace::SpanContext &parent_context,
                     [[maybe_unused]] opentelemetry::trace::TraceId trace_id,
                     [[maybe_unused]] opentelemetry::nostd::string_view name,
                     [[maybe_unused]] opentelemetry::trace::SpanKind span_kind,
                     const opentelemetry::common::KeyValueIterable &attributes,
                     [[maybe_unused]] const opentelemetry::trace::SpanContextKeyValueIterable &links) noexcept override
    {
        // Accept anything if topics == all
        if(cfg.accept_all_spans())
        {
            return {opentelemetry::sdk::trace::Decision::RECORD_AND_SAMPLE, {}, {}};
        }

        // Only accept if the span topic includes a subscribed topic
        auto findTopics = [&](auto key, auto value) -> bool
        {
            if(key == telemetry::kTelemetryTopicSpanAttribute)
            {
                std::string V;
                if(opentelemetry::nostd::holds_alternative<opentelemetry::nostd::string_view>(value))
                {
                    V = std::string{opentelemetry::nostd::get<opentelemetry::nostd::string_view>(value)};
                }
                else if(opentelemetry::nostd::holds_alternative<const char *>(value))
                {
                    V = opentelemetry::nostd::get<const char *>(value);
                }
                return !cfg.check_for_topic(V);
            }
            return true;
        };
        if(attributes.ForEachKeyValue(findTopics))
        {
            return {opentelemetry::sdk::trace::Decision::DROP, {}, {}};
        }
        return {opentelemetry::sdk::trace::Decision::RECORD_AND_SAMPLE, {}, {}};
    }

    opentelemetry::nostd::string_view GetDescription() const noexcept override
    {
        return "Topic sampler";
    }

    Configuration cfg;
};

} // namespace Tango::telemetry

#endif // TANGO_INTERNAL_TELEMETRY_TOPICSAMPLER_H
