using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using ZB.MOM.WW.MxGateway.Server;
using ZB.MOM.WW.MxGateway.Server.Dashboard;
using ZB.MOM.WW.MxGateway.Server.Dashboard.Hubs;

namespace ZB.MOM.WW.MxGateway.Tests.Gateway.Dashboard;

public sealed class DashboardHubsRegistrationTests
{
    /// <summary>Verifies that dashboard build maps all three hubs and token endpoint.</summary>
    /// <returns>A task that represents the asynchronous operation.</returns>
    [Fact]
    public async Task Build_WhenDashboardEnabled_MapsAllThreeHubsAndTokenEndpoint()
    {
        await using WebApplication app = GatewayApplication.Build([]);
        IReadOnlyList<RouteEndpoint> endpoints = ((IEndpointRouteBuilder)app).DataSources
            .SelectMany(source => source.Endpoints)
            .OfType<RouteEndpoint>()
            .ToList();

        Assert.Contains(endpoints, endpoint => endpoint.RoutePattern.RawText == "/hubs/snapshot/negotiate");
        Assert.Contains(endpoints, endpoint => endpoint.RoutePattern.RawText == "/hubs/alarms/negotiate");
        Assert.Contains(endpoints, endpoint => endpoint.RoutePattern.RawText == "/hubs/events/negotiate");
        Assert.Contains(endpoints, endpoint =>
            endpoint.Metadata.GetMetadata<IEndpointNameMetadata>()?.EndpointName == "DashboardHubToken");
    }

    /// <summary>
    /// Verifies that dashboard build registers the hub token service. It is a singleton
    /// shared by the <c>/hubs/token</c> endpoint and <c>HubTokenAuthenticationHandler</c>;
    /// there is deliberately no client-side hub-connection factory to resolve, because
    /// server-rendered pages read the in-process feeds instead of dialling their own hubs.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation.</returns>
    [Fact]
    public async Task Build_WhenDashboardEnabled_RegistersHubTokenService()
    {
        await using WebApplication app = GatewayApplication.Build([]);

        HubTokenService tokens = app.Services.GetRequiredService<HubTokenService>();
        Assert.NotNull(tokens);
    }

    /// <summary>
    /// The publish and in-process subscribe faces of the event mirror must resolve to
    /// one instance: two would leave the session-details page reading a mirror the
    /// session pipeline never publishes to, and the viewer gate would never open.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation.</returns>
    [Fact]
    public async Task Build_WhenDashboardEnabled_ResolvesBothEventMirrorInterfacesToOneInstance()
    {
        await using WebApplication app = GatewayApplication.Build([]);

        IDashboardEventBroadcaster broadcaster = app.Services.GetRequiredService<IDashboardEventBroadcaster>();
        IDashboardSessionEventSubscriber subscriber = app.Services
            .GetRequiredService<IDashboardSessionEventSubscriber>();

        Assert.Same(broadcaster, subscriber);
        Assert.Same(app.Services.GetRequiredService<DashboardEventBroadcaster>(), broadcaster);
    }
}
