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

/// <summary>
/// The kind of node within the v3 Raw project tree (<c>/raw</c>). Determines how the
/// renderer styles the row, which context-menu it shows, and which entity (if any) it
/// links to. The Raw tree is cluster-rooted and mirrors the RawPath hierarchy:
/// Enterprise → Cluster → Folder(s) → Driver → Device → TagGroup(s) → Tag.
/// </summary>
public enum RawNodeKind
{
    /// <summary>Top-level grouping label (a string on cluster rows, not a DB entity).</summary>
    Enterprise,

    /// <summary>A server cluster — the root of a Raw project tree.</summary>
    Cluster,

    /// <summary>A driver-organizing <c>RawFolder</c> (nestable under a cluster or another folder).</summary>
    Folder,

    /// <summary>A <c>DriverInstance</c>.</summary>
    Driver,

    /// <summary>A <c>Device</c> under a driver (universal in v3 — every driver has ≥1).</summary>
    Device,

    /// <summary>A tag-organizing <c>TagGroup</c> (nestable under a device or another group).</summary>
    TagGroup,

    /// <summary>A raw <c>Tag</c> (signal) — a leaf.</summary>
    Tag,
}

/// <summary>
/// View-model for a single node in the Raw project tree. Carries the stable identity,
/// display text, per-kind ids, and lazy-load metadata the renderer needs, plus transient UI
/// state (expansion/loading) that is never persisted. Detached from EF — safe to hold and
/// mutate UI state on after the loading context is disposed. This is the shared contract
/// between <see cref="IRawTreeService"/> (which produces nodes) and the <c>RawTree</c>
/// component (which renders + lazily expands them).
/// </summary>
public sealed class RawNode
{
    /// <summary>The kind of node — drives styling, context-menu, and entity linking.</summary>
    public required RawNodeKind Kind { get; init; }

    /// <summary>Stable per-node key, unique within the tree (e.g. <c>drv:{driverInstanceId}</c>).</summary>
    public required string Key { get; init; }

    /// <summary>Human-readable label shown in the tree (the node's <c>Name</c>, or Enterprise/Cluster label).</summary>
    public required string DisplayName { get; init; }

    /// <summary>Owning cluster id for every node under a cluster (and the cluster itself); null for Enterprise.</summary>
    public string? ClusterId { get; init; }

    /// <summary>
    /// This node's own logical entity id (<c>RawFolderId</c>/<c>DriverInstanceId</c>/<c>DeviceId</c>/
    /// <c>TagGroupId</c>/<c>TagId</c>, or the <c>ClusterId</c> for a cluster); null for Enterprise. The
    /// child loader keys off <see cref="Kind"/> + this id to fetch the next level.
    /// </summary>
    public string? EntityId { get; init; }

    /// <summary>
    /// The bound <c>DriverType</c> for <see cref="RawNodeKind.Driver"/> (and propagated to Device/TagGroup/Tag
    /// nodes beneath it, so tag editors and the browse-enable gate can dispatch without another query);
    /// null for folders/clusters/enterprise. Use the <c>DriverTypeNames</c> constants when matching.
    /// </summary>
    public string? DriverType { get; init; }

    /// <summary>Whether a Driver/Device node is enabled (drives the enable/disable menu label + styling); true otherwise.</summary>
    public bool Enabled { get; init; } = true;

    /// <summary>Direct child count (for the badge) — for a device, its root tag-groups + root tags (direct children only, not the whole subtree).</summary>
    public int ChildCount { get; set; }

    /// <summary>
    /// Whether this node's children load lazily on expand. True for every container kind in the Raw tree
    /// (Cluster/Folder/Driver/Device/TagGroup) — unlike the UNS tree, <c>/raw</c> actually exercises the
    /// lazy plumbing (per-device tag counts can be large). Tags are leaves (false).
    /// </summary>
    public bool HasLazyChildren { get; init; }

    /// <summary>Lazily-materialised children — empty until <see cref="Loaded"/> flips on expand.</summary>
    public List<RawNode> Children { get; } = new();

    /// <summary>Optimistic-concurrency token for this node's backing row (empty for Enterprise); echoed on mutations.</summary>
    public byte[] RowVersion { get; init; } = Array.Empty<byte>();

    // --- Runtime UI state (not persisted) ---

    /// <summary>Whether the node is currently expanded in the UI.</summary>
    public bool Expanded { get; set; }

    /// <summary>Whether the node's lazy children have been loaded.</summary>
    public bool Loaded { get; set; }

    /// <summary>Whether a lazy-load is currently in flight for this node.</summary>
    public bool Loading { get; set; }

    /// <summary>Last load error message, if any.</summary>
    public string? Error { get; set; }
}
