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

/// <summary>
/// Pure, EF-free assembly of the eager top of the Raw project tree (<c>/raw</c>) — Enterprise → Cluster —
/// from flat cluster rows. The peer of <see cref="UnsTreeAssembly"/> for the Raw subtree. Everything below
/// a cluster loads lazily via <see cref="IRawTreeService.LoadChildrenAsync"/>, so this helper only nests
/// clusters under their enterprise label and stamps each cluster with its root-level child count and the
/// lazy-load flag. Empty clusters are retained so they stay visible and authorable.
/// </summary>
public static class RawTreeAssembly
{
    /// <summary>
    /// Builds the Enterprise→Cluster roots. Ordering is deterministic and ordinal at both levels. Each
    /// cluster is marked <see cref="RawNode.HasLazyChildren"/> and carries the supplied root child count
    /// (its root folders + cluster-root drivers).
    /// </summary>
    /// <param name="clusters">The flat cluster rows to nest under their enterprise label.</param>
    /// <param name="rootChildCounts">Per-cluster count of root folders + cluster-root drivers (badge).</param>
    /// <returns>The assembled enterprise root nodes, populated down to (but not through) their clusters.</returns>
    public static IReadOnlyList<RawNode> BuildRoots(
        IReadOnlyList<ClusterRow> clusters,
        IReadOnlyDictionary<string, int> rootChildCounts)
    {
        return clusters
            .GroupBy(c => c.Enterprise, StringComparer.Ordinal)
            .OrderBy(g => g.Key, StringComparer.Ordinal)
            .Select(entGroup =>
            {
                var ent = new RawNode
                {
                    Kind = RawNodeKind.Enterprise,
                    Key = $"ent:{entGroup.Key}",
                    DisplayName = entGroup.Key,
                    ClusterId = null,
                    EntityId = null,
                    HasLazyChildren = false,
                };

                var clusterNodes = entGroup
                    .OrderBy(c => c.Name, StringComparer.Ordinal)
                    .ThenBy(c => c.ClusterId, StringComparer.Ordinal)
                    .Select(c => new RawNode
                    {
                        Kind = RawNodeKind.Cluster,
                        Key = $"clu:{c.ClusterId}",
                        DisplayName = string.IsNullOrEmpty(c.Site) ? c.Name : $"{c.Site} ({c.Name})",
                        ClusterId = c.ClusterId,
                        // A cluster's own logical id IS its ClusterId — EntityId mirrors it for uniform navigation.
                        EntityId = c.ClusterId,
                        HasLazyChildren = true,
                        ChildCount = rootChildCounts.GetValueOrDefault(c.ClusterId),
                    })
                    .ToList();

                ent.Children.AddRange(clusterNodes);
                ent.ChildCount = ent.Children.Count;
                return ent;
            })
            .ToList();
    }
}
