using ZB.MOM.WW.OtOpcUa.Commons.OpcUa;

namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;

/// <summary>
///     Production <see cref="IOpcUaAddressSpaceSink"/> binding for v2 — bridges
///     OpcUaPublishActor's writes to the SDK address space owned by
///     <see cref="OtOpcUaNodeManager"/>. The host wires this in once the StandardServer has
///     been started (so the node manager exists).
/// </summary>
public sealed class SdkAddressSpaceSink : IOpcUaAddressSpaceSink
{
    private readonly OtOpcUaNodeManager _nodeManager;

    /// <summary>Initializes a new instance of the SdkAddressSpaceSink class.</summary>
    /// <param name="nodeManager">The OPC UA node manager.</param>
    public SdkAddressSpaceSink(OtOpcUaNodeManager nodeManager)
    {
        ArgumentNullException.ThrowIfNull(nodeManager);
        _nodeManager = nodeManager;
    }

    /// <summary>Writes a value to the OPC UA address space.</summary>
    /// <param name="nodeId">The OPC UA node identifier.</param>
    /// <param name="value">The value being written.</param>
    /// <param name="quality">The OPC UA quality status.</param>
    /// <param name="sourceTimestampUtc">The source timestamp in UTC.</param>
    public void WriteValue(string nodeId, object? value, OpcUaQuality quality, DateTime sourceTimestampUtc)
        => _nodeManager.WriteValue(nodeId, value, quality, sourceTimestampUtc);

    /// <summary>Writes the full Part 9 alarm-condition state to the OPC UA address space.</summary>
    /// <param name="alarmNodeId">The alarm node identifier.</param>
    /// <param name="state">The full condition state to project onto the node.</param>
    /// <param name="sourceTimestampUtc">The source timestamp in UTC.</param>
    public void WriteAlarmCondition(string alarmNodeId, AlarmConditionSnapshot state, DateTime sourceTimestampUtc)
        => _nodeManager.WriteAlarmCondition(alarmNodeId, state, sourceTimestampUtc);

    /// <summary>Materialises a real Part 9 alarm-condition node in the address space.</summary>
    /// <param name="alarmNodeId">The alarm node identifier (== ScriptedAlarmId).</param>
    /// <param name="equipmentNodeId">The equipment folder node identifier the condition parents under.</param>
    /// <param name="displayName">The human-readable condition name.</param>
    /// <param name="alarmType">The domain alarm type.</param>
    /// <param name="severity">The domain severity.</param>
    public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity)
        => _nodeManager.MaterialiseAlarmCondition(alarmNodeId, equipmentNodeId, displayName, alarmType, severity);

    /// <summary>Ensures a folder node exists in the address space.</summary>
    /// <param name="folderNodeId">The folder node identifier.</param>
    /// <param name="parentNodeId">The parent folder node identifier.</param>
    /// <param name="displayName">The display name for the folder.</param>
    public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName)
        => _nodeManager.EnsureFolder(folderNodeId, parentNodeId, displayName);

    /// <summary>Ensures a variable node exists in the address space.</summary>
    /// <param name="variableNodeId">The variable node identifier.</param>
    /// <param name="parentFolderNodeId">The parent folder node identifier.</param>
    /// <param name="displayName">The display name for the variable.</param>
    /// <param name="dataType">The OPC UA data type.</param>
    public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType)
        => _nodeManager.EnsureVariable(variableNodeId, parentFolderNodeId, displayName, dataType);

    /// <summary>Rebuilds the entire OPC UA address space.</summary>
    public void RebuildAddressSpace() => _nodeManager.RebuildAddressSpace();
}
