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

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

/// <summary>
///     Populates the five sub-attribute references on <see cref="AlarmConditionInfo"/>
///     by Galaxy convention. The server-level <c>AlarmConditionService</c> (PR 2.2) uses
///     these to subscribe to live alarm-state attributes and to route ack writes back to
///     the alarm tag.
/// </summary>
/// <remarks>
///     Galaxy alarms expose four runtime attributes plus a write-only ack target,
///     consistently named on every alarm-bearing object:
///     <list type="bullet">
///       <item><c>&lt;tag&gt;.&lt;attr&gt;.InAlarm</c></item>
///       <item><c>&lt;tag&gt;.&lt;attr&gt;.Priority</c></item>
///       <item><c>&lt;tag&gt;.&lt;attr&gt;.DescAttrName</c></item>
///       <item><c>&lt;tag&gt;.&lt;attr&gt;.Acked</c></item>
///       <item><c>&lt;tag&gt;.&lt;attr&gt;.AckMsg</c></item>
///     </list>
///     This is the same convention the legacy <c>GalaxyAlarmTracker</c> hard-coded; we
///     concentrate it here so PR 2.2's service receives complete <c>AlarmConditionInfo</c>
///     rows during discovery without the server needing to know the convention.
/// </remarks>
internal static class AlarmRefBuilder
{
    private const string InAlarmSuffix = ".InAlarm";
    private const string PrioritySuffix = ".Priority";
    private const string DescAttrNameSuffix = ".DescAttrName";
    private const string AckedSuffix = ".Acked";
    private const string AckMsgSuffix = ".AckMsg";

    /// <summary>
    ///     Build an <see cref="AlarmConditionInfo"/> for an alarm-bearing attribute with all
    ///     five sub-attribute references populated.
    ///     <para>
    ///         v3 splits identity from dialling: <paramref name="conditionReference"/> is the alarm's
    ///         <b>RawPath</b> — the condition's stable identity, surfaced as
    ///         <see cref="AlarmConditionInfo.SourceName"/> and matched against the
    ///         <c>ConditionId</c> the driver reports on every transition and against the value
    ///         fan-out key. <paramref name="dialReference"/> is the Galaxy <b>attributeRef</b>
    ///         (<c>tag_name.AttributeName</c>, e.g. <c>"Tank1.Level.HiHi"</c>) — the address MXAccess
    ///         understands; the five live-state / ack sub-refs prefix each suffix onto it so the
    ///         server's <c>AlarmConditionService</c> subscribes + acks the dialled attributes. In the
    ///         identity case (no RawPath mapping) both arguments are the same string, reproducing the
    ///         pre-v3 shape exactly.
    ///     </para>
    /// </summary>
    /// <param name="conditionReference">The alarm condition's RawPath identity (= <see cref="AlarmConditionInfo.SourceName"/>).</param>
    /// <param name="dialReference">The Galaxy attributeRef the five sub-refs are dialled from.</param>
    /// <param name="initialSeverity">The initial alarm severity level.</param>
    /// <param name="initialDescription">The initial alarm description.</param>
    /// <returns>The populated <see cref="AlarmConditionInfo"/> with all five sub-attribute references.</returns>
    public static AlarmConditionInfo Build(
        string conditionReference,
        string dialReference,
        AlarmSeverity initialSeverity = AlarmSeverity.Medium,
        string? initialDescription = null) => new(
            SourceName: conditionReference,
            InitialSeverity: initialSeverity,
            InitialDescription: initialDescription,
            InAlarmRef: dialReference + InAlarmSuffix,
            PriorityRef: dialReference + PrioritySuffix,
            DescAttrNameRef: dialReference + DescAttrNameSuffix,
            AckedRef: dialReference + AckedSuffix,
            AckMsgWriteRef: dialReference + AckMsgSuffix);
}
