using Akka.Actor;
using Akka.Cluster.Tools.PublishSubscribe;
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Runtime.Telemetry;

namespace ZB.MOM.WW.OtOpcUa.Runtime.Drivers;

/// <summary>
///     Forwards <see cref="DriverHealth"/> transitions to the cluster-wide
///     <c>driver-health</c> DistributedPubSub topic. Consumed by the AdminUI
///     <c>DriverStatusSignalRBridge</c>.
/// </summary>
public sealed class AkkaDriverHealthPublisher : IDriverHealthPublisher
{
    /// <summary>The DistributedPubSub topic name for driver-health snapshots — single source
    /// of truth on the message contract itself.</summary>
    public const string TopicName = DriverHealthChanged.TopicName;

    private readonly ActorSystem _system;
    private readonly ITelemetryLocalHub _hub;

    /// <summary>Initializes a new instance of <see cref="AkkaDriverHealthPublisher"/>.</summary>
    /// <param name="system">The Akka actor system used to resolve the DPS mediator.</param>
    /// <param name="hub">The node-local live-telemetry hub each snapshot is also emitted into (Phase 5).</param>
    public AkkaDriverHealthPublisher(ActorSystem system, ITelemetryLocalHub hub)
    {
        _system = system;
        _hub = hub;
    }

    /// <inheritdoc />
    public void Publish(
        string clusterId,
        string driverInstanceId,
        DriverHealth health,
        int errorCount5Min,
        DateTime? rediscoveryNeededUtc = null,
        string? rediscoveryReason = null)
    {
        var msg = new DriverHealthChanged(
            clusterId,
            driverInstanceId,
            health.State.ToString(),
            health.LastSuccessfulRead,
            health.LastError,
            errorCount5Min,
            DateTime.UtcNow,
            rediscoveryNeededUtc,
            rediscoveryReason);
        DistributedPubSub.Get(_system).Mediator.Tell(new Publish(TopicName, msg));
        // Phase 5: fan the same snapshot into the node-local live-telemetry hub (no-op until a gRPC
        // client subscribes). The DPS publish above is unchanged — the hub is a strictly additive tap.
        _hub.Emit(new TelemetryItem.Health(msg));
    }
}
