using Akka.Actor;
using Akka.Event;
using ZB.MOM.WW.OtOpcUa.Commons.Types;
namespace ZB.MOM.WW.OtOpcUa.Runtime.OpcUa;
///
/// Single-threaded bridge between Akka messages and the OPC UA SDK address space. Hosted on
/// the pinned opcua-synchronized-dispatcher (Task 19 HOCON) so the OPC UA SDK sees
/// only one thread per actor instance — its session/subscription locks expect strict
/// single-threaded access.
///
/// Engine wiring (call into OpcUaApplicationHost address-space writes, manage
/// ServiceLevel + ServerUriArray nodes, subscribe to the redundancy-state
/// DistributedPubSub topic) is staged for follow-up F10. This skeleton compiles + exposes the
/// message contracts so producers (DriverInstance, VirtualTag, ScriptedAlarm) can target it.
///
public sealed class OpcUaPublishActor : ReceiveActor
{
public const string DispatcherId = "opcua-synchronized-dispatcher";
public sealed record AttributeValueUpdate(string NodeId, object? Value, OpcUaQuality Quality, DateTime TimestampUtc);
public sealed record AlarmStateUpdate(string AlarmNodeId, bool Active, bool Acknowledged, DateTime TimestampUtc);
public sealed record RebuildAddressSpace(CorrelationId Correlation);
public sealed record ServiceLevelChanged(byte ServiceLevel);
public enum OpcUaQuality { Good, Uncertain, Bad }
private readonly ILoggingAdapter _log = Context.GetLogger();
private int _writes;
///
/// Returns Props pre-configured to use the opcua-synchronized-dispatcher. Caller can
/// still override by chaining .WithDispatcher(otherId) for unit tests.
///
public static Props Props() =>
Akka.Actor.Props.Create(() => new OpcUaPublishActor()).WithDispatcher(DispatcherId);
/// Test-only Props that omits the pinned dispatcher requirement.
public static Props PropsForTests() =>
Akka.Actor.Props.Create(() => new OpcUaPublishActor());
public int WriteCount => _writes;
public OpcUaPublishActor()
{
Receive(msg =>
{
// F10: call into OpcUaApplicationHost to write the address-space node.
Interlocked.Increment(ref _writes);
_log.Debug("OpcUaPublish: queued AttributeValueUpdate for {Node} ({Quality}) (write staged for F10)",
msg.NodeId, msg.Quality);
});
Receive(msg =>
{
Interlocked.Increment(ref _writes);
_log.Debug("OpcUaPublish: queued AlarmStateUpdate for {Node} (active={Active})",
msg.AlarmNodeId, msg.Active);
});
Receive(msg =>
{
_log.Info("OpcUaPublish: address-space rebuild requested (correlation={Correlation}); F10 wires the SDK call",
msg.Correlation);
});
Receive(msg =>
{
_log.Debug("OpcUaPublish: ServiceLevel={Level} (write staged for F10)", msg.ServiceLevel);
});
}
}