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

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

/// <summary>
/// InboundAPI-008 / InboundAPI-022: 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. This gate
/// mirrors the leadership check in <see cref="ActiveNodeHealthCheck"/> (the
/// node is the cluster leader, <see cref="MemberStatus.Up"/>), 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);
            var self = cluster.SelfMember;
            if (self.Status != MemberStatus.Up)
                return false;

            var leader = cluster.State.Leader;
            return leader != null && leader == self.Address;
        }
    }
}
