using Microsoft.Extensions.Configuration;
using ZB.MOM.WW.LocalDb.Replication;
using ZB.MOM.WW.OtOpcUa.Commons.Observability;
using ZB.MOM.WW.Telemetry;

namespace ZB.MOM.WW.OtOpcUa.Host.Observability;

/// <summary>
/// Wires the OtOpcUa Meter + ActivitySource into OpenTelemetry and exposes a Prometheus
/// scrape endpoint at <c>/metrics</c> on the host pipeline. F13d slice — only the meter +
/// activity source declared in <see cref="OtOpcUaTelemetry"/> are surfaced; per-Akka
/// internals + ASP.NET request metrics stay off by default to keep the scrape payload
/// scoped to OtOpcUa-owned signals.
/// </summary>
public static class ObservabilityExtensions
{
    /// <summary>Adds OtOpcUa observability (metrics and tracing) to the service collection.</summary>
    /// <param name="services">The service collection to add observability services to.</param>
    /// <param name="configuration">
    /// Configuration read for the opt-in OTLP exporter. <c>OtOpcUa:Telemetry:Exporter</c>
    /// (parsed case-insensitively to <see cref="ZbExporter"/>) switches to OTLP when set to
    /// <c>Otlp</c>; <c>OtOpcUa:Telemetry:OtlpEndpoint</c> sets the OTLP endpoint. With no
    /// config the exporter stays Prometheus (the default).
    /// </param>
    /// <returns>The service collection, for chaining.</returns>
    public static IServiceCollection AddOtOpcUaObservability(this IServiceCollection services, IConfiguration configuration)
    {
        return services.AddZbTelemetry(o =>
        {
            o.ServiceName = "otopcua";
            // o.Meters is a STRICT allowlist — ZbTelemetry adds only the named meters, with no
            // wildcard. The LocalDb replication engine publishes under its own meter name, so
            // without this entry its localdb.sync.* / localdb.oplog.depth series are silently absent
            // from /metrics on driver nodes (the exact omission a ScadaBridge live gate caught).
            o.Meters = [OtOpcUaTelemetry.MeterName, LocalDbMetrics.MeterName];
            o.ActivitySources = [OtOpcUaTelemetry.ActivitySourceName];
            if (Enum.TryParse<ZbExporter>(configuration["OtOpcUa:Telemetry:Exporter"], ignoreCase: true, out var exporter))
                o.Exporter = exporter;
            var otlp = configuration["OtOpcUa:Telemetry:OtlpEndpoint"];
            if (!string.IsNullOrWhiteSpace(otlp))
                o.OtlpEndpoint = otlp;
        });
    }

    /// <summary>
    /// Mounts the Prometheus <c>/metrics</c> scrape endpoint on the existing ASP.NET pipeline.
    /// The endpoint is explicitly marked <c>AllowAnonymous</c> so unauthenticated Prometheus
    /// scrapers can reach it regardless of the host's auth fallback policy (which on admin-role
    /// nodes is <c>RequireAuthenticatedUser</c>). This mirrors the behaviour of
    /// <c>MapZbHealth</c>, which also marks its endpoints anonymous.
    /// </summary>
    /// <param name="app">The endpoint route builder.</param>
    /// <returns>The endpoint route builder, for chaining.</returns>
    public static IEndpointRouteBuilder MapOtOpcUaMetrics(this IEndpointRouteBuilder app)
    {
        app.MapZbMetrics().AllowAnonymous();
        return app;
    }
}
