using ZB.MOM.WW.OtOpcUa.Core.Abstractions;

namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Runtime;

/// <summary>
///     PR 6.1 — Decorator that emits one <see cref="System.Diagnostics.Activity"/> span
///     per gw write batch. Tags secured-write counts so ops can see the routing-by-
///     classification split (FreeAccess/Operate vs Tune/Configure) without re-reading
///     the discovery dictionary.
/// </summary>
internal sealed class TracedGalaxyDataWriter(IGalaxyDataWriter inner, string clientName) : IGalaxyDataWriter
{
    /// <inheritdoc />
    public void InvalidateHandleCaches() => inner.InvalidateHandleCaches();

    /// <inheritdoc />
    public async Task<IReadOnlyList<WriteResult>> WriteAsync(
        IReadOnlyList<WriteRequest> writes,
        Func<string, SecurityClassification> securityResolver,
        CancellationToken cancellationToken)
    {
        using var activity = GalaxyTelemetry.ActivitySource.StartActivity("galaxy.write");
        activity?.SetTag("galaxy.client", clientName);
        activity?.SetTag("galaxy.tag_count", writes.Count);

        if (activity is { IsAllDataRequested: true })
        {
            // Counting the secured-write split is cheap (one resolver call per request)
            // and only happens when a tracing listener is actively recording — keeps the
            // hot path free when no one's listening.
            var securedCount = 0;
            foreach (var w in writes)
            {
                var sc = securityResolver(w.FullReference);
                if (sc is SecurityClassification.Tune
                    or SecurityClassification.Configure
                    or SecurityClassification.VerifiedWrite)
                {
                    securedCount++;
                }
            }
            activity.SetTag("galaxy.secured_write_count", securedCount);
        }

        try
        {
            var results = await inner.WriteAsync(writes, securityResolver, cancellationToken)
                .ConfigureAwait(false);
            activity?.SetTag("galaxy.success_count", results.Count(r => r.StatusCode < 0x80000000u));
            return results;
        }
        catch (Exception ex)
        {
            activity.RecordError(ex);
            throw;
        }
    }
}
