use crate::observability::config::{MetricsConfig, OtlpProtocol};
use crate::observability::otlp_http::build_no_proxy_http_client;
use crate::observability::remote::append_otlp_path;
use anyhow::{bail, Context as AnyhowContext, Result};
use opentelemetry::KeyValue;
use opentelemetry_otlp::{MetricExporter, Protocol, WithExportConfig, WithHttpConfig};
use opentelemetry_sdk::{metrics::SdkMeterProvider, metrics::Temporality, Resource};

/// Builds the OpenTelemetry metrics provider.
pub fn build_metrics_provider(config: &MetricsConfig) -> Result<SdkMeterProvider> {
    if config.exporter != "otlp" {
        bail!("unsupported metrics exporter `{}`", config.exporter);
    }

    let exporter = match config.protocol {
        OtlpProtocol::HttpBinary => MetricExporter::builder()
            .with_http()
            .with_http_client(build_no_proxy_http_client()?)
            .with_protocol(Protocol::HttpBinary)
            .with_endpoint(append_otlp_path(&config.endpoint, "/v1/metrics"))
            .with_temporality(Temporality::LowMemory)
            .build(),
        OtlpProtocol::Grpc => MetricExporter::builder()
            .with_tonic()
            .with_endpoint(config.endpoint.clone())
            .with_temporality(Temporality::LowMemory)
            .build(),
    }
    .context("failed to create OpenTelemetry metrics exporter")?;

    let provider = SdkMeterProvider::builder()
        .with_periodic_exporter(exporter)
        .with_resource(resource(config))
        .build();

    Ok(provider)
}

fn resource(config: &MetricsConfig) -> Resource {
    let mut builder = Resource::builder().with_service_name(config.service_name.clone());
    if let Some(version) = &config.service_version {
        builder = builder.with_attribute(KeyValue::new("service.version", version.clone()));
    }
    builder.build()
}