using Akka.Cluster;
using ZB.MOM.WW.ScadaBridge.Host.Actors;
using ZB.MOM.WW.ScadaBridge.InboundAPI;

namespace ZB.MOM.WW.ScadaBridge.Host.Health;

/// <summary>
/// Production implementation of
/// <see cref="IActiveNodeGate"/> backed by the running Akka.NET cluster.
///
/// The inbound API is "Central cluster only (active node)" — a standby central
/// node must not execute method scripts or <c>Route.To()</c> calls. Active =
/// the oldest Up member (the singleton host), evaluated by
/// <see cref="ClusterActivityEvaluator.SelfIsOldest(Cluster, string?)"/> — NOT
/// the cluster leader, whose address-ordered definition diverges from singleton
/// placement after a restart (review 01 [High]). This is the same evaluator
/// backing the shared <c>ActiveNodeHealthCheck</c> registered on the active tier
/// — both route to <c>ClusterActiveNode</c> — so
/// <see cref="InboundApiEndpointFilter"/> can return HTTP 503 on a standby.
///
/// Registered only in the Central-role branch of <c>Program.cs</c>. The gate
/// is resolved per request from <c>HttpContext.RequestServices</c>; while the
/// <c>AkkaHostedService</c> is still warming up (<c>ActorSystem == null</c>)
/// or the node has not yet reached <see cref="MemberStatus.Up"/>, this
/// implementation reports <c>IsActiveNode == false</c> — the safe-by-default
/// answer matching the standby case.
/// </summary>
public sealed class ActiveNodeGate : IActiveNodeGate
{
    private readonly AkkaHostedService _akkaService;

    /// <summary>Initializes a new <see cref="ActiveNodeGate"/> bound to the given Akka hosted service.</summary>
    /// <param name="akkaService">The Akka hosted service exposing the cluster's <see cref="Akka.Actor.ActorSystem"/>.</param>
    public ActiveNodeGate(AkkaHostedService akkaService)
    {
        _akkaService = akkaService;
    }

    /// <inheritdoc />
    public bool IsActiveNode
    {
        get
        {
            var system = _akkaService.ActorSystem;
            if (system == null)
                return false;

            var cluster = Cluster.Get(system);
            return ClusterActivityEvaluator.SelfIsOldest(cluster);
        }
    }
}
