namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;

/// <summary>
///     Which authoring surface a proposed effective name comes from. Used to word the collision
///     error and to exclude the correct same-kind self-row on an edit (rename / override change).
/// </summary>
public enum EffectiveNameSourceKind
{
    /// <summary>A <see cref="Configuration.Entities.UnsTagReference"/> (effective name =
    /// <c>DisplayNameOverride</c> else the backing raw tag's <c>Name</c>).</summary>
    Reference,

    /// <summary>An equipment-bound <see cref="Configuration.Entities.VirtualTag"/> (effective name = <c>Name</c>).</summary>
    VirtualTag,

    /// <summary>An equipment-bound <see cref="Configuration.Entities.ScriptedAlarm"/> (effective name = <c>Name</c>).</summary>
    ScriptedAlarm,
}

/// <summary>
///     v3 Batch 3 authoring-time guard for the UNS effective-name uniqueness rule. Within an
///     equipment the EFFECTIVE leaf name must be unique across its <c>UnsTagReferences</c>
///     (<c>DisplayNameOverride</c> else the backing raw tag's <c>Name</c>), its <c>VirtualTags</c>
///     (<c>Name</c>), and its <c>ScriptedAlarms</c> (<c>Name</c>) — the three share the equipment's
///     UNS NodeId space (<c>{EquipmentId}/{EffectiveName}</c>). This is the authoring mirror of the
///     deploy-time <c>DraftValidator</c> <c>UnsEffectiveNameCollision</c> rule; comparison is
///     <see cref="StringComparer.Ordinal"/> to match NodeId semantics and the validator.
/// </summary>
/// <remarks>
///     Injectable (registered <c>Scoped</c>, its own pooled context per call — the same pattern
///     <c>UnsTreeService</c> uses). Consumed by <c>UnsTreeService</c>'s reference / virtual-tag /
///     scripted-alarm mutations, which call <see cref="CheckAsync"/> before persisting and surface a
///     non-null result as the mutation's readable failure. The deploy gate remains the backstop for
///     rename-induced collisions the authoring check never saw.
/// </remarks>
public interface IEffectiveNameGuard
{
    /// <summary>
    ///     Tests whether <paramref name="proposedEffectiveName"/> would collide with an existing
    ///     effective name within <paramref name="equipmentId"/>.
    /// </summary>
    /// <param name="equipmentId">The owning equipment's logical id.</param>
    /// <param name="proposedEffectiveName">The effective name to be authored (override else raw name for a reference; Name for a VT/alarm).</param>
    /// <param name="kind">Which surface the proposed name is for (words the error; identifies the self-row kind to exclude).</param>
    /// <param name="excludeSourceId">
    ///     On an edit, the logical id of the row being changed (its <c>UnsTagReferenceId</c> /
    ///     <c>VirtualTagId</c> / <c>ScriptedAlarmId</c>) so it is excluded from the collision set;
    ///     <see langword="null"/> on a create.
    /// </param>
    /// <param name="ct">Cancellation token.</param>
    /// <returns>
    ///     <see langword="null"/> when the name is free; otherwise a readable error naming the
    ///     colliding existing source and the equipment.
    /// </returns>
    Task<string?> CheckAsync(
        string equipmentId,
        string proposedEffectiveName,
        EffectiveNameSourceKind kind,
        string? excludeSourceId,
        CancellationToken ct = default);
}
