using Microsoft.AspNetCore.SignalR;
using ZB.MOM.WW.OtOpcUa.Admin.Hubs;

namespace ZB.MOM.WW.OtOpcUa.Admin.Services;

/// <summary>
///     Thin SignalR push helper for ACL + role-grant invalidation — slice 2 of task #196.
///     Lets the Admin services + razor pages invalidate connected peers' views without each
///     one having to know the hub wiring. Two message kinds: <c>NodeAclChanged</c> (cluster-scoped)
///     and <c>RoleGrantsChanged</c> (fleet-wide — role mappings cross cluster boundaries).
/// </summary>
/// <remarks>
///     Intentionally fire-and-forget — a failed hub send doesn't rollback the DB write that
///     triggered it. Worst-case an operator sees stale data until their next poll or manual
///     refresh; better than a transient hub blip blocking the authoritative write path.
/// </remarks>
public sealed class AclChangeNotifier(IHubContext<FleetStatusHub> fleetHub, ILogger<AclChangeNotifier> logger)
{
    public async Task NotifyNodeAclChangedAsync(string clusterId, long generationId, CancellationToken ct)
    {
        try
        {
            var msg = new NodeAclChangedMessage(ClusterId: clusterId, GenerationId: generationId, ObservedAtUtc: DateTime.UtcNow);
            await fleetHub.Clients.Group(FleetStatusHub.GroupName(clusterId))
                .SendAsync("NodeAclChanged", msg, ct).ConfigureAwait(false);
        }
        catch (Exception ex) when (ex is not OperationCanceledException)
        {
            logger.LogWarning(ex, "NodeAclChanged push failed for cluster {ClusterId} gen {GenerationId}", clusterId, generationId);
        }
    }

    public async Task NotifyRoleGrantsChangedAsync(CancellationToken ct)
    {
        try
        {
            var msg = new RoleGrantsChangedMessage(ObservedAtUtc: DateTime.UtcNow);
            await fleetHub.Clients.Group(FleetStatusHub.FleetGroup)
                .SendAsync("RoleGrantsChanged", msg, ct).ConfigureAwait(false);
        }
        catch (Exception ex) when (ex is not OperationCanceledException)
        {
            logger.LogWarning(ex, "RoleGrantsChanged push failed");
        }
    }
}

public sealed record NodeAclChangedMessage(string ClusterId, long GenerationId, DateTime ObservedAtUtc);
public sealed record RoleGrantsChangedMessage(DateTime ObservedAtUtc);
