using System.Linq;

namespace ZB.MOM.NatsNet.Server;

internal sealed partial class JetStream
{
    internal ClusterInfo? OfflineClusterInfo(RaftGroup? group)
    {
        var server = Server as NatsServer;
        if (server == null || group == null)
            return null;

        var clusterInfo = new ClusterInfo
        {
            Name = server.ClusterName(),
            Replicas = group.Peers
                .Select(peer =>
                {
                    var info = server.GetNodeInfo(peer);
                    return new PeerInfo
                    {
                        Name = info?.Name ?? peer,
                        Current = false,
                        Offline = true,
                        Active = TimeSpan.Zero,
                        Lag = 0,
                    };
                })
                .ToArray(),
        };

        return clusterInfo;
    }

    internal ClusterInfo? ClusterInfo(RaftGroup? group)
    {
        var server = Server as NatsServer;
        if (server == null)
            return null;

        _mu.EnterReadLock();
        try
        {
            if (group?.Node == null)
            {
                return new ClusterInfo
                {
                    Name = server.CachedClusterName(),
                    Leader = server.ServerName(),
                };
            }

            var node = group.Node;
            var leaderNode = node.GroupLeader();
            var peerInfos = new List<PeerInfo>();
            var now = DateTime.UtcNow;
            var ourId = node.ID();

            foreach (var peer in node.Peers())
            {
                if (string.Equals(peer.Id, ourId, StringComparison.Ordinal))
                    continue;
                if (!group.IsMember(peer.Id))
                    continue;

                var nodeInfo = server.GetNodeInfo(peer.Id);
                var active = peer.Last == default || now <= peer.Last ? TimeSpan.Zero : now - peer.Last;
                peerInfos.Add(new PeerInfo
                {
                    Name = nodeInfo?.Name ?? peer.Id,
                    Current = peer.Current,
                    Offline = nodeInfo?.Offline ?? true,
                    Active = active,
                    Lag = peer.Lag,
                });
            }

            return new ClusterInfo
            {
                Name = server.CachedClusterName(),
                Leader = server.ServerNameForNode(leaderNode),
                Replicas = peerInfos.OrderBy(r => r.Name, StringComparer.Ordinal).ToArray(),
            };
        }
        finally
        {
            _mu.ExitReadLock();
        }
    }
}
