using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using Shouldly;
using Xunit;
using ZB.MOM.WW.Health;
using ZB.MOM.WW.Health.Akka;
using ZB.MOM.WW.OtOpcUa.Host.Health;

namespace ZB.MOM.WW.OtOpcUa.Host.Tests.Health;

/// <summary>
/// Pins OtOpcUa's active-tier wiring. The <i>rule</i> (oldest Up member of a role) now lives in the
/// shared <c>ClusterActiveNode</c> and is tested there against a real two-node cluster; what stays
/// OtOpcUa's own decision — and what regressed in <c>lmxopcua#494</c> — is <b>which check is
/// registered on the active tag, and with which roles</b>.
/// </summary>
public sealed class ActiveTierRegistrationTests
{
    private static HealthCheckRegistration ClusterPrimaryRegistration(bool hasAdmin) =>
        new ServiceCollection()
            .AddOtOpcUaHealth(hasAdmin)
            .BuildServiceProvider()
            .GetRequiredService<IOptions<HealthCheckServiceOptions>>()
            .Value.Registrations
            .Where(r => r.Name == "cluster-primary")
            .ShouldHaveSingleItem();

    [Fact]
    public void Active_tier_uses_the_shared_ActiveNodeHealthCheck()
    {
        // Not a bespoke copy. Two apps in the family independently hand-rolled this check because the
        // shared one selected by RoleLeader; since Health 0.3.0 the shared one is the correct rule, so
        // a private reimplementation reappearing here would be the regression.
        var registration = ClusterPrimaryRegistration(hasAdmin: true);

        registration.Factory(new ServiceCollection().BuildServiceProvider())
            .ShouldBeOfType<ActiveNodeHealthCheck>();
    }

    [Theory]
    [InlineData(true)]
    [InlineData(false)]
    public void Active_tier_check_is_registered_on_every_node_role(bool hasAdmin)
    {
        // Registered on driver-only nodes too, unlike the admin-only configdb probe. A site pair needs
        // an active tier just as much as the central pair does — under the old admin-scoped check all
        // four driver-only site nodes answered 200 and no consumer could find a site's Primary.
        ClusterPrimaryRegistration(hasAdmin).Tags.ShouldContain(ZbHealthTags.Active);
    }

    [Fact]
    public void Active_tier_check_is_not_on_the_ready_tier()
    {
        // Readiness must not depend on being the active node: a healthy standby is ready to serve, and
        // tagging it ready would take the whole pair out of rotation whenever one node is standby.
        ClusterPrimaryRegistration(hasAdmin: true).Tags.ShouldNotContain(ZbHealthTags.Ready);
    }
}
