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

/// <summary>
///     Streaming builder API a driver uses to register OPC UA nodes during discovery.
///     Core owns the tree; driver streams <c>AddFolder</c> / <c>AddVariable</c> calls
///     as it discovers nodes — no buffering of the whole tree.
/// </summary>
/// <remarks>
///     Per <c>docs/v2/plan.md</c> decision #52 — drivers register nodes via this builder
///     rather than returning a tree object. Supports incremental / large address spaces
///     without forcing the driver to buffer the whole tree.
/// </remarks>
public interface IAddressSpaceBuilder
{
    /// <summary>
    ///     Add a folder node. Returns a child builder scoped to inside this folder, so subsequent
    ///     calls on the child place nodes under it.
    /// </summary>
    /// <param name="browseName">OPC UA browse name (the segment of the path under the parent).</param>
    /// <param name="displayName">Human-readable display name. May equal <paramref name="browseName"/>.</param>
    IAddressSpaceBuilder Folder(string browseName, string displayName);

    /// <summary>
    ///     Add a variable node corresponding to a tag. Driver-side full reference + data-type
    ///     metadata come from the <see cref="DriverAttributeInfo"/> DTO.
    /// </summary>
    /// <param name="browseName">OPC UA browse name (the segment of the path under the parent folder).</param>
    /// <param name="displayName">Human-readable display name. May equal <paramref name="browseName"/>.</param>
    /// <param name="attributeInfo">Driver-side metadata for the variable.</param>
    IVariableHandle Variable(string browseName, string displayName, DriverAttributeInfo attributeInfo);

    /// <summary>
    ///     Add a property to the current node (folder or variable). Properties are static metadata
    ///     read once at build time (e.g. OPC 40010 Identification fields per the schemas-repo
    ///     <c>_base</c> equipment-class template).
    /// </summary>
    void AddProperty(string browseName, DriverDataType dataType, object? value);
}

/// <summary>Opaque handle for a registered variable. Used by Core for subscription routing.</summary>
public interface IVariableHandle
{
    /// <summary>Driver-side full reference for read/write addressing.</summary>
    string FullReference { get; }

    /// <summary>
    ///     Annotate this variable with an OPC UA <c>AlarmConditionState</c>. Drivers with
    ///     <see cref="DriverAttributeInfo.IsAlarm"/> = true call this during discovery so the
    ///     concrete address-space builder can materialize a sibling condition node. The returned
    ///     sink receives lifecycle transitions raised through <see cref="IAlarmSource.OnAlarmEvent"/>
    ///     — the generic node manager wires the subscription; the concrete builder decides how
    ///     to surface the state (e.g. OPC UA <c>AlarmConditionState.Activate</c>,
    ///     <c>Acknowledge</c>, <c>Deactivate</c>).
    /// </summary>
    IAlarmConditionSink MarkAsAlarmCondition(AlarmConditionInfo info);
}

/// <summary>
///     Metadata used to materialize an OPC UA <c>AlarmConditionState</c> sibling for a variable.
///     Populated by the driver's discovery step; concrete builders decide how to surface it.
/// </summary>
/// <param name="SourceName">Human-readable alarm name used for the <c>SourceName</c> event field.</param>
/// <param name="InitialSeverity">Severity at address-space build time; updates arrive via <see cref="IAlarmConditionSink"/>.</param>
/// <param name="InitialDescription">Initial description; updates arrive via <see cref="IAlarmConditionSink"/>.</param>
public sealed record AlarmConditionInfo(
    string SourceName,
    AlarmSeverity InitialSeverity,
    string? InitialDescription);

/// <summary>
///     Sink a concrete address-space builder returns from <see cref="IVariableHandle.MarkAsAlarmCondition"/>.
///     The generic node manager routes per-alarm <see cref="IAlarmSource.OnAlarmEvent"/> payloads here —
///     the sink translates the transition into an OPC UA condition state change or whatever the
///     concrete builder's backing address space supports.
/// </summary>
public interface IAlarmConditionSink
{
    /// <summary>Push an alarm transition (Active / Acknowledged / Inactive) for this condition.</summary>
    void OnTransition(AlarmEventArgs args);
}
