namespace ZB.MOM.WW.OtOpcUa.Commons.Browsing;
/// One node in a driver-agnostic browse tree.
/// Stable identifier passed back to the picker on commit. For OPC UA
/// this is the nsu=...;... form; for Galaxy this is the tag_name.
/// Label shown in the tree.
/// Whether this node terminates the address (Leaf) or has children
/// (Folder). Galaxy never returns Leaves; only the attribute side-panel terminates.
/// When true, the UI renders an expand affordance before
/// the children have been fetched.
public sealed record BrowseNode(
string NodeId,
string DisplayName,
BrowseNodeKind Kind,
bool HasChildrenHint);
/// Discriminates terminal vs. expandable nodes for UI rendering.
public enum BrowseNodeKind
{
/// Expandable — has (or may have) children. UI shows expand affordance.
Folder,
/// Terminal — commit on select.
Leaf,
}
/// Metadata for an attribute of a Galaxy object (or the equivalent
/// per-driver concept). Surfaced in the picker's attribute side-panel.
/// True when this attribute is itself an alarm condition (Galaxy: carries an
/// AlarmExtension primitive). The picker pre-fills a default native-alarm alarm object
/// into the TagConfig when an alarm attribute is selected. Defaults to false so non-alarm-aware
/// drivers (e.g. the OPC UA client browser) aren't forced to flow a flag they don't produce.
///
/// The structured address this leaf binds by, as TagConfig key → value in the
/// driver's own key vocabulary, for a driver whose address is a tuple rather than a single
/// reference string. Null (the default) for every driver whose address IS the
/// — nothing changes for them.
///
/// It exists because a tuple cannot be recovered from an id string in general. MQTT/Sparkplug
/// is the case in point: a browse node id is
/// {group}/{node}[/{device}]::{metric}, and a metric name may itself contain /
/// (Node Control/Rebirth) — so the session keeps the decomposition it already has and
/// states it here, rather than the AdminUI's browse-commit mapper re-deriving it by
/// splitting the id and hoping. Same discipline as the v3 address space carrying
/// AddressSpaceRealm explicitly instead of parsing it out of a NodeId.
///
///
/// The producer states the binding shape too, by which keys it emits — so a consumer
/// never has to infer a driver's sub-mode from the tree's geometry. Consumers must read the
/// keys they know and ignore the rest; this is a description, not a config blob to splat into
/// a persisted TagConfig.
///
///
public sealed record AttributeInfo(
string Name,
string DriverDataType,
bool IsArray,
string SecurityClass,
bool IsAlarm = false,
IReadOnlyDictionary? AddressFields = null);